2017-04-21 4 views
2

나는 수입을 맨 위 선언으로 옮겨서 이미 나의 문제를 해결했다. 궁금한 점이있다. 의 대상이되는 함수에서 '__main__'으로 가져온 모듈을 사용할 수없는 이유는 무엇입니까? 예를 들어왜 '__main__'모듈을 가져 오면 멀티 프로세스가 모듈을 사용할 수 없습니까?

:

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'은 메인 스크립트를 생성하는 각 파이썬 서브 프로세스로'import'합니다. 따라서'if __name__ == '__main __''은'False'가됩니다. 스크립트에서,'run()'이 실행될 때 모듈이'arcpy' 모듈을 가져 오지 않았 음을 의미합니다. 왜냐하면 프로세스가 완전히 다른 메모리 공간에서 실행되기 때문입니다. – martineau

답변

3

유닉스 계열 시스템과 Windows에서는 상황이 다릅니다. Unixy 시스템에서 multiprocessingfork을 사용하여 상위 메모리 공간의 쓰기 중 복사보기를 공유하는 하위 프로세스를 만듭니다. 하위 항목은 if __name__ == "__main__": 아래에 가져온 부모를 포함하여 상위 항목에서 가져온 항목을 확인합니다.

윈도우에서는 포크가 없으므로 새로운 프로세스가 실행되어야합니다. 그러나 단순히 부모 프로세스를 재실행하면 작동하지 않습니다. 전체 프로그램을 다시 실행하게됩니다. 대신, multiprocessing은 부모 메인 스크립트를 가져온 자신의 python 프로그램을 실행 한 다음, 자식 프로세스를위한 충분한 부모 객체 공간의 뷰를 pickle/unpickle합니다.

해당 프로그램은 하위 프로세스의 경우 __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__)) 

은 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에서는 "importing 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