2014-01-27 22 views
0

以下是使用線程輸出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

我寫了一小段代碼來說明如何使用隊列到你的線程在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 

我希望這足以讓您開始。

+0

謝謝,那是我想到的一種方法:讓我的主線程創建一個作業池,同時一個單獨的作業運行線程池運行並運行當前可用的任何作業。我不知道該從哪裏開始,所以這有很大的幫助。 – MxyL