2017-04-21 75 views
2

我已經通過將導入移動到頂部聲明來解決了我的問題,但它讓我想知道:爲什麼我不能使用在'__main__'中導入的模塊作爲multiprocessing的目標函數?爲什麼'__main__'中的導入模塊不允許multiprocessig使用模塊?

例如:

import os 
import multiprocessing as mp 

def run(in_file, out_dir, out_q): 
    arcpy.RaterToPolygon_conversion(in_file, out_dir, "NO_SIMPIFY", "Value") 
    status = str("Done with "+os.path.basename(in_file)) 
    out_q.put(status, block=False) 

if __name__ == '__main__': 
    raw_input("Program may hang, press Enter to import ArcPy...") 
    import arcpy 

    q = mp.Queue() 
    _file = path/to/file 
    _dir = path/to/dir 
    # There are actually lots of files in a loop to build 
    # processes but I just do one for context here 
    p = mp.Process(target=run, args=(_file, _dir, q)) 
    p.start() 

# I do stuff with Queue below to status user 

當你運行這個在IDLE不會錯誤在所有...只是一直在做一個Queue檢查(這是個好所以沒有問題)。問題是,當你在CMD終端(無論是OS還是Python)中運行它時,會產生arcpy未定義的錯誤!

只是一個好奇的話題。

+0

你在linux或windows上運行嗎? – tdelaney

+0

@tdelaney Windows,這就是爲什麼我使用'if __name__'語句。 –

+0

在WIndows中,'multiprocessing'有效''將主腳本導入到它生成的每個Python子進程中,所以'if __name__ =='__main __''在這些情況下將是'False'。在你的腳本中,這意味着當'run()'被執行時,模塊'arcpy'不會被導入,因爲它所處理的進程在完全獨立的內存空間中執行。 – martineau

回答

3

類似unix的系統和Windows的情況不同。在unixy系統上,multiprocessing使用fork來創建共享父內存空間的寫時複製視圖的子進程。孩子看到父母的進口,包括父母根據if __name__ == "__main__":導入的任何東西。

在windows上,沒有fork,必須執行新的進程。但簡單地重新運行父進程不起作用 - 它會再次運行整個程序。相反,multiprocessing運行它自己的python程序,該程序導入父主腳本,然後醃/取消父對象空間的視圖,希望對子進程足夠了。

該程序是子進程的__main__,並且父腳本的__main__未運行。主腳本只是像其他任何模塊一樣導入。原因很簡單:運行父代__main__將再次運行完整的父程序,mp必須避免。

這是一個測試,以顯示正在發生的事情。稱爲testmp.py的主模塊和由第一模塊導入的第二模塊test2.py

testmp.py

import os 
import multiprocessing as mp 

print("importing test2") 
import test2 

def worker(): 
    print('worker pid: {}, module name: {}, file name: {}'.format(os.getpid(), 
     __name__, __file__)) 

if __name__ == "__main__": 
    print('main pid: {}, module name: {}, file name: {}'.format(os.getpid(), 
     __name__, __file__)) 
    print("running process") 
    proc = mp.Process(target=worker) 
    proc.start() 
    proc.join() 

test2.py

import os 

print('test2 pid: {}, module name: {}, file name: {}'.format(os.getpid(), 
     __name__, __file__)) 

在Linux上運行,test2的是進口的,一旦與勞動者在主模塊中運行。

importing test2 
test2 pid: 17840, module name: test2, file name: /media/td/USB20FD/tmp/test2.py 
main pid: 17840, module name: __main__, file name: testmp.py 
running process 
worker pid: 17841, module name: __main__, file name: testmp.py 

在windows下,請注意「導入test2」打印兩次 - testmp.py運行兩次。但「主要pid」只打印一次 - 其未運行__main__。這是因爲multiprocessing在導入過程中將模塊名稱更改爲__mp_main__

E:\tmp>py testmp.py 
importing test2 
test2 pid: 7536, module name: test2, file name: E:\tmp\test2.py 
main pid: 7536, module name: __main__, file name: testmp.py 
running process 
importing test2 
test2 pid: 7544, module name: test2, file name: E:\tmp\test2.py 
worker pid: 7544, module name: __mp_main__, file name: E:\tmp\testmp.py 
+0

我的'mp。Process()每次都不會重新運行'__main__'嗎?我只是想讓每個子進程在'def run()'中運行代碼。 –

+0

不,但是它重新導入你的主模塊並調用它'__mp_main__'。這就是爲什麼你隱藏你不想在'if __name__ =='__main __「:'下重新運行的東西。我已經用演示更新了答案。 – tdelaney

+0

在Windows中兒童啓動顯着更昂貴 - 執行新的python副本並導入模塊。 – tdelaney

相關問題