0

저는 Ubuntu 16.04.2 LTS와 Python 3.5.2를 사용하고 있습니다. 나는 ThreadPool에서 multiprocessing 일을하고 있습니다. 이제 작업을 수행하는 동안이 풀을 종료하고 싶습니다.Python 3 : 멀티 프로세싱에서 스레드 종료 ThreadPool이 작동하지 않습니다.

ThreadPool.terminate()을 사용하면 예상대로 작동하지 않습니다. 다음 예제를 실행하면 작업자가 작업을 중단하지 않으며 프로그램이 ThreadPool.join() 호출을지나 실행되지 않습니다.

import time 
from multiprocessing.pool import ThreadPool 

def task(): 
    try: 
     while True: 
      print("Working") 
      time.sleep(1) 
    except: # Unsuccessful attempt. :(
     print("Working, stopping now") 

thread_pool = ThreadPool(processes=1) 

thread_pool.apply_async(task) 
time.sleep(1) # Make sure the task is actually started. 

print("Terminating") 
thread_pool.terminate() 
print("Termination: Initiated") 
thread_pool.join() # Does not return. 
print("Termination: Done") 

내가 뭘 잘못하고 있니?

답변

1

구체적으로 Pool이 아닌 ThreadPool을 요청했습니다. 즉, 새 프로세스를 만드는 대신 multiprocessing 코드가 자신의 프로세스에서 로컬 스레드를 생성합니다.

ThreadPool 인스턴스는 (시스템이 os.kill을 호출 할 수있는 프로세스와 달리) 정의 된 메커니즘이 없으므로 갑자기 종료 될 수 없습니다. 코드에서 .terminate 지시어는 무시됩니다. 사실, 이것은 풀 인스턴스가 태스크가 리턴 할 때 검사 할 플래그를 설정하지만 태스크는 리턴하지 않습니다.

$ python3 tp.py 
Working on 0 with i = 0 
Working on 0 with i = 1 
Terminating 
Termination: Initiated 
Working on 0 with i = 2 
Termination: Done 

--delay 5으로 실행할 때 :

$ python3 tp.py --delay 5 
Working on 0 with i = 0 
Working on 0 with i = 1 
Working on 0 with i = 2 
Working on 1 with i = 0 
Working on 1 with i = 1 
Terminating 
Working on 1 with i = 2 
Termination: Initiated 
Termination: Done 

다른 방법으로, 경우 인수없이 실행하면이 작업을 수행하는

import argparse 
import sys 
import time 

from multiprocessing.pool import Pool, ThreadPool 

def task(arg): 
    for i in range(3): 
     print("Working on", arg, "with i =", i) 
     time.sleep(1) 

def main(): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('--delay', default=1, type=float) 
    args = parser.parse_args() 

    thread_pool = ThreadPool(processes=1) 

    thread_pool.apply_async(task, (0,)) 
    thread_pool.apply_async(task, (1,)) 
    time.sleep(args.delay) 

    print("Terminating") 
    thread_pool.terminate() 
    print("Termination: Initiated") 
    thread_pool.join() # Does not return. 
    print("Termination: Done") 

if __name__ == '__main__': 
    try: 
     sys.exit(main()) 
    except KeyboardInterrupt: 
     sys.exit('\nInterrupted') 

: 우리는 수정 된 버전이를 볼 수 있습니다 ThreadPool 대신 Pool을 사용하면 실제 프로세스를 얻을 수 있으며 언제든지 .terminate을 사용할 수 있습니다 (일반적인 c 통신 대기열을 망쳐 버릴 수 있습니다.)

+0

감사합니다. 스레드 대신 프로세스를 사용하는 실제 다중 처리 구현에 대해 알고 있었지만 응용 프로그램에 스레드를 사용해야합니다. 그러나, 나는'ThreadPool.terminate()'의 구현이 실제로 그 방법이라는 것을 몰랐다. 거기에 내가 (아마도 모든 단일 작업에 대한) 종료 통신 기능을 구현하지 않고도 사용할 수있는'ThreadPool'에 대한 대안이 있습니까? 작업에서 예외를 잡는 것과 같은 일을하는 것은 물론 괜찮습니다. – mxscho

+0

파이썬이 제공하는 것보다 낮은 레벨에 있다면, 특정 스레드에 신호를 보낼 수 있습니다. 메커니즘은 (분명히) 기계에 달려 있습니다. 일부 시스템에는 (FreeBSD 용) 스레드 시그널 핸들링에도 여러 가지 버그가 있었으며, 이는 파이썬에서 해결 방법이있을 수 있으므로 간섭을 일으킬 수 있으므로 실험을 통해 시스템에서 작동하는지 확인해야합니다. 이 작업을 수행 할 수있는 휴대용 방식은 공유 "시간 정지"를 설정하는 것입니다. 변수를 확인하고 주기적으로 점검하십시오. – torek

관련 문제