我知道有像 Parallel 这样的伟大宝石,但我想出了下面的课程作为练习。
它工作正常,但是当进行大量迭代时,有时 Ruby 会“卡住”。当按下 CTRL+CI 时,可以从回溯中看到它总是在第 38 行或第 45 行(两条 Marshal 行)。你能看出这里有什么问题吗?管道似乎“挂起”,所以我想我可能以错误的方式使用它们。
我的目标是使用有限数量的分叉 (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