Ruby变量引用问题

时间:2013-11-19 07:50:38

标签: ruby

我不熟悉ruby并且遇到以下代码示例时遇到问题。我想将数组索引传递给线程函数。当我运行此代码时,所有线程都打印“4”。他们应该打印“0 1 2 3 4”(以任何顺序)。

似乎num变量在循环的所有迭代之间共享,并传递对“test”函数的引用。循环在线程开始之前完成,num等于4。

发生了什么以及如何获得正确的行为?

NUM_THREADS = 5

def test(num)
    puts num.to_s()
end

threads = Array.new(NUM_THREADS)

for i in 0..(NUM_THREADS - 1)
    num = i
    threads[i] = Thread.new{test(num)}
end

for i in 0..(NUM_THREADS - 1)
    threads[i].join
end

2 个答案:

答案 0 :(得分:1)

“发生什么事了?” => num的范围是主要环境,因此它由所有线程共享(围绕它的唯一事情是for关键字,它不创建范围)。所有线程中puts的执行晚于for i循环,将其递增到4。作为参数传递给线程的变量(例如下面的num)将成为块参数,并且不会在线程外部共享。

NUM_THREADS = 5
threads = Array.new(NUM_THREADS){|i| Thread.new(i){|num| puts num}}.each(&:join)

答案 1 :(得分:1)

你的脚本完成了我在Unix中的期望,但在Windows中却没有,很可能是因为线程实例化与for循环竞争使用num值。我认为原因是for循环没有创建闭包,所以在完成循环后num等于4

for i in 0..4
end
puts i
# => 4

要修复它(并编写更多惯用的Ruby),你可以写下这样的东西:

NUM_THREADS = 5

def test(num)
  puts num  # to_s is unnecessary
end

# Create an array for each thread that runs test on each index
threads = NUM_THREADS.times.map { |i| Thread.new { test i } }

# Call the join method on each thread
threads.each(&:join)

其中imap块的本地。

相关问题