반응형
Ctrl + C / SIGINT를 잡아 파이썬에서 우아하게 다중 프로세스를 종료합니다.
다중 프로세스 파이썬 프로그램에서 Ctrl + C를 잡고 모든 프로세스를 정상적으로 종료하려면 어떻게해야합니까? 유닉스와 Windows 모두에서 작동하는 솔루션이 필요합니다. 나는 다음을 시도했다 :
import multiprocessing
import time
import signal
import sys
jobs = []
def worker():
signal.signal(signal.SIGINT, signal_handler)
while(True):
time.sleep(1.1234)
print "Working..."
def signal_handler(signal, frame):
print 'You pressed Ctrl+C!'
# for p in jobs:
# p.terminate()
sys.exit(0)
if __name__ == "__main__":
for i in range(50):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
그리고 그것은 일종의 효과가 있지만 올바른 해결책이라고 생각하지 않습니다.
편집 : 이의 중복 될 수 이것
이전에 승인 솔루션은 경쟁 조건을 가지고 있으며, 그것은 작동하지 않습니다 map
및 async
기능.
Ctrl + C를 처리하는 올바른 방법은 / SIGINT
로는 multiprocessing.Pool
에 있습니다 :
SIGINT
프로세스Pool
가 생성 되기 전에 프로세스를 무시 합니다. 이렇게 생성 된 자식 프로세스는SIGINT
처리기를 상속 합니다.- 가 생성 된
SIGINT
후 부모 프로세스에서 원래 처리기를 복원합니다Pool
. - 사용
map_async
하고apply_async
대신에 차단map
하고apply
. - 기본 차단 대기는 모든 신호를 무시하므로 시간 초과와 함께 결과를 기다립니다. 이것은 Python 버그 https://bugs.python.org/issue8296 입니다.
종합 :
#!/bin/env python
from __future__ import print_function
import multiprocessing
import os
import signal
import time
def run_worker(delay):
print("In a worker process", os.getpid())
time.sleep(delay)
def main():
print("Initializng 2 workers")
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
pool = multiprocessing.Pool(2)
signal.signal(signal.SIGINT, original_sigint_handler)
try:
print("Starting 2 jobs of 5 seconds each")
res = pool.map_async(run_worker, [5, 5])
print("Waiting for results")
res.get(60) # Without the timeout this blocking call ignores all signals.
except KeyboardInterrupt:
print("Caught KeyboardInterrupt, terminating workers")
pool.terminate()
else:
print("Normal termination")
pool.close()
pool.join()
if __name__ == "__main__":
main()
@YakovShklarov가 언급했듯이 신호를 무시하고 부모 프로세스에서 신호를 무시하지 않는 사이에는 신호가 손실 될 수있는 기간이 있습니다. 사용하여 pthread_sigmask
일시적으로 손실되는 신호를 방해하는 부모 프로세스에서 신호의 전달을 차단하는 대신에, 그러나, 파이썬-2에서 사용할 수 없습니다.
The solution is based on this link and this link and it solved the problem, I had to moved to Pool
though:
import multiprocessing
import time
import signal
import sys
def init_worker():
signal.signal(signal.SIGINT, signal.SIG_IGN)
def worker():
while(True):
time.sleep(1.1234)
print "Working..."
if __name__ == "__main__":
pool = multiprocessing.Pool(50, init_worker)
try:
for i in range(50):
pool.apply_async(worker)
time.sleep(10)
pool.close()
pool.join()
except KeyboardInterrupt:
print "Caught KeyboardInterrupt, terminating workers"
pool.terminate()
pool.join()
Just handle KeyboardInterrupt-SystemExit exceptions in your worker process:
def worker():
while(True):
try:
msg = self.msg_queue.get()
except (KeyboardInterrupt, SystemExit):
print("Exiting...")
break
반응형
'IT박스' 카테고리의 다른 글
CascadeType.REFRESH는 실제로 무엇을합니까? (0) | 2020.10.17 |
---|---|
Django에서 현재 로그인 한 사용자를 어떻게 알 수 있습니까? (0) | 2020.10.17 |
Elasticsearch 데이터를 한 서버에서 다른 서버로 이동하는 방법 (0) | 2020.10.16 |
TypeScript "저장시 컴파일"기능이 Visual Studio 2015에서 작동하지 않음 (0) | 2020.10.16 |
빠른 쿼리는 SSRS에서 느리게 실행됩니다. (0) | 2020.10.16 |