-2

我想创建一个脚本来计算多个线程中的数字。每个线程将计算 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
4

3 回答 3

1

我建议您阅读Pragmatic Programmer 的 ruby​​ 书的“线程和进程”一章。这是网上的旧版本。名为“创建 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不使用换行符的命令,因为后者将换行符作为单独的指令打印,这可能会被另一个线程中断。

于 2012-09-13T17:50:25.397 回答
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
于 2012-09-13T18:22:52.833 回答
0

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

threads = (1..3).map do |i|
  puts "I'm starting thread no #{i}"
  Thread.new { loopa(2**i) }
end
于 2012-09-13T17:53:04.523 回答