我不熟悉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
答案 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)
其中i
是map
块的本地。