ruby中的多线程计算

时间:2012-09-13 17:11:52

标签: ruby multithreading

我想创建一个脚本来计算多个线程中的数字。每个线程将计算2的幂,但第一个线程必须从2开始计算,第二个线程从4开始计算,第三个线程从8开始计算,在中间打印一些文本。

示例:

Im a thread and these are my results
2
4
8
Im a thread and these are my results
4
8
16
Im a thread and these are my results
8
16
32

我的失败代码:

def loopa(s)
    3.times do
        puts s
        s=s**2
    end
end
threads=[]
num=2
until num == 8 do
    threads << Thread.new{ loopa(num) }
    num=num**2
end
threads.each { |x| puts "Im a thread and these are my results" ; x.join }

我的失败结果:

Im a thread and these are my results
8
64
4096
8
64
4096
8
64
4096
Im a thread and these are my results
Im a thread and these are my results

3 个答案:

答案 0 :(得分:1)

我建议你阅读“主题和流程”章节实用程序员的红宝石书。这是一个old version在线。名为“创建Ruby线程”的部分与您的问题特别相关。

要解决此问题,您需要将Thread.new行更改为:

threads << Thread.new(num){|n| loopa(n) }

您的版本不起作用,因为num在线程之间共享,并且可能被另一个线程更改。通过块传递变量,不再共享块变量。

更多信息

另外,你的数学错误。 输出值为:

Thread 1: 2 4 16
Thread 2: 4 16 256
Thread 3: 6 36 1296

从未达到“8”因为until条件一看到“8”就退出。

如果您想要更清晰的输出,请将其用作loopa

的正文
3.times do
    print "#{Thread.current}: #{s}\n"
    s=s**2
end

这可以让你区分3个线程。请注意,最好使用带有换行符的字符串的print命令而不使用不带换行符的puts,因为后者将换行符作为单独的指令打印,可能会被另一个线程中断。 / p>

答案 1 :(得分:0)

这很正常。读你写的东西。首先,您运行3个异步线程,因此输出将在各种线程输出组合中。然后你写'我是一个线程,这些是我的结果'并加入每个线程。还记得Ruby只有引用。因此,如果您将num传递给线程然后更改它,它将在所有线程中更改。为了避免它写:

threads = (1..3).map do |i|
  puts "I'm starting thread no #{i}"
  Thread.new { loopa(2**i) }
end

答案 2 :(得分:0)

我觉得需要发布一个数学上正确的版本:

def loopa(s)
  3.times do
      print "#{Thread.current}: #{s}\n"
      s *= 2
  end
end

threads=[]
num=2
while num <= 8 do
    threads << Thread.new(num){|n| loopa(n) }
    num *= 2
end

threads.each { |x| print "Im a thread and these are my results\n" ; x.join }

奖金1:无线解决方案(天真)

power = 1
workers = 3
iterations = 3

(power ... power + workers).each do |pow|
  worker_pow = 2 ** pow
  puts "I'm a worker and these are my results"
  iterations.times do |inum|
    puts worker_pow
    worker_pow *= 2
  end
end

奖金2:无线解决方案(缓存)

power = 1
workers = 3
iterations = 3

cache_size = workers + iterations - 1
# generate all the values upfront
cache = []
(power ... power+cache_size).each do |i|
  cache << 2**i
end

workers.times do |wnum|
  puts "I'm a worker and these are my results"
  # use a sliding-window to grab the part of the cache we want
  puts cache[wnum,3]
end