2017-06-06 43 views
1

有人能幫我理解下面的代碼片段嗎?我知道我不能使用全局變量使用multiprocessing,但我仍然對我看到的結果感到驚訝。多處理和全局文件句柄的怪異行爲

我在不同的工作進程中遠程執行的函數內使用全局文件句柄。

import multiprocessing 
import os 

fh = open("out.txt", "w") 

def process(i): 
    print("i={} pid={} id(fh)={}".format(i, os.getpid(), id(fh))) 
    print(i, file=fh) 

def main(): 
    p = multiprocessing.Pool(3) 
    p.map(process, (1, 2, 3)) 
    p.terminate() 
    fh.close() 

main() 

輸出是

i=1 pid=92045 id(fh)=4314964256 
i=2 pid=92046 id(fh)=4314964256 
i=3 pid=92047 id(fh)=4314964256 

所以我們看到,有三個不同的進程ID預期。

什麼suprises我:

  1. 的unpickable文件句柄可在工作進程
  2. id計算的內存地址是所有工人
  3. 工作進程可以寫入該文件相同句柄沒有拋出異常
  4. 儘管如此,程序執行後文件是空的。

回答

1

找到答案自己:

  1. 的unpickable文件句柄可在工作進程:從Python解釋器過程,因此在內存中複製的全局變量multiprocessing叉(SO後multiprocessing global variable memory copying) 。在子解釋器中調用函數時,變量的酸洗只發生在函數參數中。
  2. 由id計算出的內存地址對所有worker都是一樣的:顯示的內存地址是虛擬地址空間內的地址,因此是相對的。分叉後的初始內存佈局是一樣的。 (SO張貼Fork - same memory addresses?
  3. 工作進程可以寫入到該文件句柄未拋出異常:見答案1 + 爲叉形過程fh底層fileno是相同的。
  4. 儘管如此,在程序執行後文件爲空:如果我在返回process之前調用flush方法,則該文件不是空的。所以當進程被它的父進程終止時,文件緩衝區不會被刷新。

備註: 我的示例在Windows上的行爲應該不同。由於不同的流程模型/實現,Windows上的multiprocessing必須啓動新的Python解釋器。