2009-07-02 75 views
23

如果我做從派生進程

Process.fork do 
    x 
end 

我怎麼能知道X返回什麼(例如真/ FASE /串)返回的數據?

(寫入文件/數據庫不是一個選項...)

回答

9

我將沿途發現的所有解決方案(如用戶退出+管道緩衝區等一些其他問題)包裝爲ruby parallel gem。現在,它是那麼容易,因爲:

results = Parallel.map([1,2,3],:in_processes=>4) do |i| 
    execute_something(i) 
end 

results = Parallel.map([1,2,3],:in_threads=>4) do |i| 
    execute_something(i) 
end 
0

根據文檔:

如果指定了一個塊,該塊是在子進程運行,並且子進程終止狀態爲零。

所以,如果你有一個塊中調用它,則返回0。否則,它的功能基本相同,在Unix上fork()系統調用(父接收新進程的PID,孩子接受nil)。

+0

這怎麼能幫助得到什麼的 'X' 回來了? – grosser 2009-07-02 19:43:40

+0

子進程運行在一個單獨的進程中(很明顯),因此要獲取任何「x」的值,您可能必須通過套接字,管道或類似的東西進行通信。我懷疑你可以,例如在塊內部設置變量,因爲子進程具有單獨的內存等。 – mipadi 2009-07-02 19:51:29

0

兩個Unix進程之間的fork通信主要是返回碼,僅此而已。但是,您可以在兩個進程之間打開一個文件描述符,並通過此文件描述符在進程之間傳遞數據:這是普通的Unix管道方式。

如果您要傳遞Marshal.dump()和Marshal.load()值,那麼您可以輕鬆地在這些Ruby進程之間傳遞Ruby對象。

0

如果孩子只需要一小段代碼就可以使用共享內存來做到這一點。像下面的內容將工作:

str = 'from parent' 

Thread.new do 
    str = 'from child' 
end 

sleep(1) 

puts str # outputs "from child" 

併發性可能會非常棘手,雖然和訪問共享內存這種方式的很大一部分原因 - 你已經有了一個變量,另一個進程可能會改變它的任何時間從你的下面出來,你應該非常謹慎。或者,您可以使用管道,這種管道比較笨重,但對於最簡單的代碼可能更安全,也可以用來運行任意命令。下面是一個例子,直出的RDoc爲IO.popen的:

f = IO.popen("uname") 
p f.readlines  # outputs "Darwin", at least on my box :-) 
30

實際上,我們剛剛在Rails isolation testing來處理這個問題。我發佈了一些關於它的一些on my blog

基本上,你想要做的是在父母和孩子中打開一個管道,並讓孩子寫入管道。這裏有一個簡單的方法來運行一個塊的內容在一個子進程,並取回結果:

def do_in_child 
    read, write = IO.pipe 

    pid = fork do 
    read.close 
    result = yield 
    Marshal.dump(result, write) 
    exit!(0) # skips exit handlers. 
    end 

    write.close 
    result = read.read 
    Process.wait(pid) 
    raise "child failed" if result.empty? 
    Marshal.load(result) 
end 

然後,你可以運行:

do_in_child do 
    require "some_polluting_library" 
    SomePollutingLibrary.some_operation 
end 

請注意,如果你做一個在孩子需要,您將無法訪問父庫中的該庫,因此無法使用此方法返回該類型的對象。但是,您可以返回任何可用的類型。

還要注意很多的細節在這裏(read.closeProcess.wait2(pid))大都是看家的細節,所以如果你使用這個有很多你應該移到了這一點,到公共圖書館,你可以重複使用。

最後,請注意,這不適用於Windows或JRuby,因爲它們不支持分叉。

11

感謝所有的答案,我得到了我的解決方案和運行,還需要了解如何處理非分叉的環境,但現在它的工作原理:)

read, write = IO.pipe 
Process.fork do 
    write.puts "test" 
end 
Process.fork do 
    write.puts 'test 2' 
end 

Process.wait 
Process.wait 

write.close 
puts read.read 
read.close 

,你可以看到它在行動@parallel_specs Rails plugin

+0

你見過我在答案中提供的隔離測試鏈接嗎?它可以處理分叉和非分叉環境,並且可能已經做好了你需要的一切。 – 2009-07-02 21:21:36

1

是的,你可以創建一個子進程來執行內部塊。

我建議the aw gem

Aw.fork! { 6 * 7 } # => 42 

當然,它可以防止副作用:

arr = ['foo'] 
Aw.fork! { arr << 'FUU' } # => ["foo", "FUU"] 
arr # => ["foo"]