Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby threads and variable

Why the result is not from 1 to 10, but 10s only?

require 'thread'

def run(i)
  puts i
end

while true
  for i in 0..10
    Thread.new{ run(i)}
  end
  sleep(100)
end

Result:

10
10
10
10
10
10
10
10
10
10
10

Why loop? I am running while loop, because later I want to iterate through the DB table all the time and echo any records that are retrieved from the DB.

like image 562
meso_2600 Avatar asked Jul 11 '14 21:07

meso_2600


2 Answers

The block that is passed to Thread.new may actually begin at some point in the future, and by that time the value of i may have changed. In your case, they all have incremented up to 10 prior to when all the threads actually run.

To fix this, use the form of Thread.new that accepts a parameter, in addition to the block:

require 'thread'

def run(i)
  puts i
end

while true
  for i in 0..10
    Thread.new(i) { |j| run(j) }
  end
  sleep(100)
end

This sets the block variable j to the value of i at the time new was called.

like image 61
Matt Avatar answered Sep 18 '22 12:09

Matt


@DavidGrayson is right.

You can see here a side effect in for loop. In your case i variable scope is whole your file. While you are expecting only a block in your for loop as a scope. Actually this is wrong approach in idiomatic Ruby. Ruby gives you iterators for this job.

(1..10).each do |i|
   Thread.new{ run(i)}
end

In this case scope of variable i will be isolated in block scope what means for each iteration you will get new local (for this block) variable i.

like image 20
fl00r Avatar answered Sep 18 '22 12:09

fl00r