[英]Ruby 1.8.7: Forks & Pipes - Troubleshooting
我知道有很多類似Parallel的寶石,但是我想出了以下課程作為練習。
它工作正常,但是在進行大量迭代時,有時會發生Ruby被“卡住”的情況。 當按下CTRL + CI時,從回溯中可以看到它總是在第38或45行(兩條元帥行)中。 您能在這里看到什么不對嗎? 似乎是管道在“掛”,所以我認為我可能以錯誤的方式使用它們。
我的目標是使用數量有限的fork(max_forks)遍歷一個數組(我將其作為“對象”傳遞)並返回一些值。 另外,我想保證在父母被殺死時所有孩子都被殺死(即使在kill -9的情況下),這就是為什么我引入了“ life_line”管道的原因(我在Stackoverflow上閱讀過這可能會達到目的) 。
class Parallel
def self.do_fork(max_forks, objects)
waiter_threads = []
fork_counter = []
life_line = {}
comm_line = {}
objects.each do |object|
key = rand(24 ** 24).to_s(36)
sleep(0.01) while fork_counter.size >= max_forks
if fork_counter.size < max_forks
fork_counter << true
life_line[key] = {}
life_line[key][:r], life_line[key][:w] = IO.pipe
comm_line[key] = {}
comm_line[key][:r], comm_line[key][:w] = IO.pipe
pid = fork {
life_line[key][:w].close
comm_line[key][:r].close
Thread.new {
begin
life_line[key][:r].read
rescue SignalException, SystemExit => e
raise e
rescue Exception => e
Kernel.exit
end
}
Marshal.dump(yield(object), comm_line[key][:w]) # return yield
}
waiter_threads << Thread.new {
Process.wait(pid)
comm_line[key][:w].close
reply = Marshal.load(comm_line[key][:r])
# process reply here
comm_line[key][:r].close
life_line[key][:r].close
life_line[key][:w].close
life_line[key] = nil
fork_counter.pop
}
end
end
waiter_threads.each { |k| k.join } # wait for all threads to finish
end
end
錯誤是這樣的:
管道只能處理一定數量的數據(例如64 KB)。 一旦編寫了更多內容,管道將永遠“卡住”。
一個簡單的解決方案是在開始寫入線程之前先在線程中讀取它。
comm_line = IO.pipe
# Buffered Pipe Reading (in case bigger than 64 KB)
reply = ""
read_buffer = Thread.new {
while !comm_line[0].eof?
reply = Marshal.load(comm_line[0])
end
}
child_pid = fork {
comm_line[0].close
comm_line[0].write "HUGE DATA LARGER THAN 64 KB"
}
Process.wait(child_pid)
comm_line[1].close
read_buffer.join
comm_line[0].close
puts reply # outputs the "HUGE DATA"
我認為元帥沒有問題。 似乎更明顯的是,您的fork可能在等待服務程序線程到達之前完成執行(導致后者永遠等待)。
嘗試將Process.wait(pid)
更改為Process.wait(pid, Process::WNOHANG)
。 如果沒有子級(匹配給定的PID,如果有),則Process::WNOHANG
標志指示Ruby不要掛起。 請注意,此功能可能並非在所有平台上都可用,但至少應在Linux上有效。
您的代碼還有許多其他潛在的問題,但是如果您只是“作為練習”提出來的話,它們可能無關緊要。 例如,Marshal.load不喜歡遇到EOF,因此我可能會說Marshal.load(comm_line[key][:r]) unless comm_line[key][:r].eof?
類的東西來防范這些情況, Marshal.load(comm_line[key][:r]) unless comm_line[key][:r].eof?
或循環until comm_line[key][:r].eof?
如果您希望讀取多個對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.