簡體   English   中英

Ruby 1.8.7:分支和管道-故障排除

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM