将任务分配给空闲的线程

时间:2014-01-27 00:11:20

标签: ruby multithreading

这是一个使用线程打印100个数字的脚本。订单无关紧要;只要打印出100个数字。我想用10个线程来完成这项工作,每个线程都做相互排斥的任务。

根据ruby docs提供的示例,我写了这个

$threads = []

def make_thread(id, num)
  t = Thread.new do
    sleep(60) if id == 0
    p num
  end
  $threads.push(t)
end

100.times do |i|
  make_thread(i % 10, i)
  if $threads.size > 10
    $threads.each {|t| t.join }
    $threads.clear
  end
end

但是,一个线程总是需要很长时间才能完成。在这种情况下,它会在它完成任务之前休眠60秒。

因为我正在迭代每个线程并调用join,所以Ruby会等到所有线程完成任务后再返回,正如预期的那样。

我如何更改代码,以便在继续之前不等待所有线程完成,而是将一个任务分配给一个线程(如果有的话)并且仅在没有线程可用的情况下等待?

当前的实现只是每次我想运行一个任务时创建一个新线程,但是只要坚持一个现有线程并告诉它做其他事情可能会很好吗?

1 个答案:

答案 0 :(得分:1)

我写了一小段代码来说明如何使用队列来同步Ruby中的线程(我试图保持简短):

require 'thread'

$pm = Mutex.new         # mutex to print on screen
$queue = Queue.new      # input queue
$oks = Queue.new        # output queue

10.times do |i|
  Thread.new(i) do |j|
    loop do
      m = $queue.pop
      $pm.synchronize { puts "pop#{j}! #{m}" }
      $oks.push('ok')
    end
  end
end

100.times { |i| $queue.push(i) }

sleep 1 while $oks.length < 100

这里我创建了10个带有无限循环的线程,关键是Queue将在pop上创建一个线程块,直到某些东西可用,并且您可以拥有任意数量的消费者。第二个Queue仅用作示例中的计数器。

有一点需要注意的是,创建任务的循环不会等待,因此如果线程处理数据的速度很慢,最终可能会有90个项目在$queue中等待。如果它太多,您可以通过将循环更改为:

来最小化负载
100.times do |i|
  sleep 1 while $queue.length > 10
  $queue.push(i)
end

我希望这足以让你开始。