通常我们一个一个地迭代一个数组:
a = [1, 2, 3, 4]
b = []
a.each do |x|
b << x * 5
end
b = [5, 10, 15, 20]
如果我不关心数组中内容的顺序,而是想通过并发运行乘法运算来提高迭代速度怎么办?例如,这样的结果是可以接受的:
b = [15, 10, 5, 20] # or
b = [5, 20, 15, 10] # or
b = [20, 15, 5, 10]
我怎么做?
通常我们一个一个地迭代一个数组:
a = [1, 2, 3, 4]
b = []
a.each do |x|
b << x * 5
end
b = [5, 10, 15, 20]
如果我不关心数组中内容的顺序,而是想通过并发运行乘法运算来提高迭代速度怎么办?例如,这样的结果是可以接受的:
b = [15, 10, 5, 20] # or
b = [5, 20, 15, 10] # or
b = [20, 15, 5, 10]
我怎么做?
由于 GIL,MRI 不能实现真正的多核并行;线程实际上并没有让你在 CPU 密集型任务上提高性能(尽管它肯定在 IO 密集型任务上确实如此);您需要运行 JRuby 或 Rubinius 才能获得 CPU 密集型任务的并行性,因为它们实际上可以同时在多个内核上分配工作。
也就是说,假设您正在运行提供真正并行性的 VM:
b = a.map {|x|
Thread.new {
Thread.current[:out] = x * 5
}
}.map {|t| t.join; t[:out] }
(这段代码非常难看,应该重构以供实际使用。它还将按照线程创建的顺序返回结果,同时仍然并行化任务。)
这里的要点是 1)在线程局部变量中传播返回值(因此您不必对共享值执行可能的非原子操作;如果您想这样做,您需要引入互斥锁),以及2) 调用#join
创建的每个线程,这样我们就可以确定创建的每个线程都运行完了。