IT TIP

다중 스레드 Python 프로그램 종료

itqueen 2020. 10. 29. 20:17
반응형

다중 스레드 Python 프로그램 종료


Ctrl + C 키 이벤트에 다중 스레드 Python 프로그램 응답을 만드는 방법은 무엇입니까?

편집 : 코드는 다음과 같습니다.

import threading
current = 0

class MyThread(threading.Thread):
    def __init__(self, total):
        threading.Thread.__init__(self)
        self.total = total

    def stop(self):
        self._Thread__stop()

    def run(self):
        global current
        while current<self.total:
            lock = threading.Lock()
            lock.acquire()
            current+=1
            lock.release()
            print current

if __name__=='__main__':

    threads = []
    thread_count = 10
    total = 10000
    for i in range(0, thread_count):
        t = MyThread(total)
        t.setDaemon(True)
        threads.append(t)
    for i in range(0, thread_count):
        threads[i].start()

모든 스레드에서 join ()을 제거하려고했지만 여전히 작동하지 않습니다. 각 스레드의 run () 프로 시저 내부의 잠금 세그먼트 때문입니까?

편집 : 위의 코드는 작동해야하지만 현재 변수가 5,000-6,000 범위에있을 때 항상 중단되고 아래와 같은 오류가 발생합니다.

Exception in thread Thread-4 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner
  File "test.py", line 20, in run
<type 'exceptions.TypeError'>: unsupported operand type(s) for +=: 'NoneType' and 'int'
Exception in thread Thread-2 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner
  File "test.py", line 22, in run

기본 스레드를 제외한 모든 스레드를 데몬으로 만듭니다 ( t.daemon = True2.6 이상 t.setDaemon(True)에서는 2.6 이하에서는 t시작하기 전에 모든 스레드 개체 에 대해). 이렇게하면 메인 스레드가 KeyboardInterrupt를 수신 할 때이를 포착하지 못하거나 포착하지만 어쨌든 종료하기로 결정하면 전체 프로세스가 종료됩니다. 문서를 참조하십시오 .

편집 : 방금 OP의 코드 (원래 게시되지 않음)와 "작동하지 않는다"라는 주장을 보았을 때 추가해야하는 것 같습니다 ... :

물론 메인 스레드가 응답 성을 유지하기를 원한다면 (예 : control-C), join다른 스레드 를 사용 하는 것과 같이 호출을 차단하지 마십시오. 특히 데몬 스레드 를 사용 하는 것과 같이 완전히 쓸모없는 호출을 차단 하지 마십시오 . 예를 들어, 메인 스레드의 최종 루프를 현재에서 변경하십시오 (완전하고 손상됨).join

for i in range(0, thread_count):
    threads[i].join()

다음과 같이 더 현명한 것으로 바꾸십시오.

while threading.active_count() > 0:
    time.sleep(0.1)

메인이 모든 스레드가 자체적으로 종료하거나 control-C (또는 기타 신호)를 수신하는 것보다 더 나은 것이없는 경우.

물론, 당신의 쓰레드가 갑자기 종료되는 것을 원하지 않는다면 (데몬 쓰레드가 그러 하듯이) 사용 가능한 패턴이 많이 있습니다 .- 그들 역시 무조건적으로 차단하는 호출, 교착 상태 등에서 영원히 빠져 나가지 않는 한 ;-) .


두 가지 주요 방법이 있습니다. 하나는 깔끔하고 하나는 쉬운 방법입니다.

깨끗한 방법은 메인 스레드에서 KeyboardInterrupt를 포착하고 백그라운드 스레드가 종료 할 수 있도록 확인할 수있는 플래그를 설정하는 것입니다. 전역을 사용하는 단순 / 약간 지저분한 버전은 다음과 같습니다.

exitapp = False
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        exitapp = True
        raise

def threadCode(...):
    while not exitapp:
        # do work here, watch for exitapp to be True

지저분하지만 쉬운 방법은 KeyboardInterrupt를 잡아서 모든 스레드를 즉시 종료하는 os._exit ()를 호출하는 것입니다.


노동자는 당신을 위해 도움이 될 수 있습니다

#!/usr/bin/env python

import sys, time
from threading import *
from collections import deque

class Worker(object):
    def __init__(self, concurrent=1):
        self.concurrent = concurrent
        self.queue = deque([])
        self.threads = []
        self.keep_interrupt = False

    def _retain_threads(self):
        while len(self.threads) < self.concurrent:
            t = Thread(target=self._run, args=[self])
            t.setDaemon(True)
            t.start()
            self.threads.append(t)


    def _run(self, *args):
        while self.queue and not self.keep_interrupt:
            func, args, kargs = self.queue.popleft()
            func(*args, **kargs)

    def add_task(self, func, *args, **kargs):
        self.queue.append((func, args, kargs))

    def start(self, block=False):
        self._retain_threads()

        if block:
            try:
                while self.threads:
                    self.threads = [t.join(1) or t for t in self.threads if t.isAlive()]
                    if self.queue:
                        self._retain_threads()
            except KeyboardInterrupt:
                self.keep_interrupt = True
                print "alive threads: %d; outstanding tasks: %d" % (len(self.threads), len(self.queue))
                print "terminating..."


# example
print "starting..."
worker = Worker(concurrent=50)

def do_work():
    print "item %d done." % len(items)
    time.sleep(3)

def main():
    for i in xrange(1000):
        worker.add_task(do_work)
    worker.start(True)

main()
print "done."

# to keep shell alive
sys.stdin.readlines()

차라리이 블로그 게시물 에서 제안한 코드를 사용 하겠습니다 .

def main(args):

    threads = []
    for i in range(10):
        t = Worker()
        threads.append(t)
        t.start()

    while len(threads) > 0:
        try:
            # Join all threads using a timeout so it doesn't block
            # Filter out threads which have been joined or are None
            threads = [t.join(1000) for t in threads if t is not None and t.isAlive()]
        except KeyboardInterrupt:
            print "Ctrl-c received! Sending kill to threads..."
            for t in threads:
                t.kill_received = True

What I have changed is the t.join from t.join(1) to t.join(1000). The actual number of seconds does not matter, unless you specify a timeout number, the main thread will stay responsive to Ctrl+C. The except on KeyboardInterrupt makes the signal handling more explicit.


You can always set your threads to "daemon" threads like:

t.daemon = True
t.start()

And whenever the main thread dies all threads will die with it.

http://www.regexprn.com/2010/05/killing-multithreaded-python-programs.html


If you spawn a Thread like so - myThread = Thread(target = function) - and then do myThread.start(); myThread.join(). When CTRL-C is initiated, the main thread doesn't exit because it is waiting on that blocking myThread.join() call. To fix this, simply put in a timeout on the .join() call. The timeout can be as long as you wish. If you want it to wait indefinitely, just put in a really long timeout, like 99999. It's also good practice to do myThread.daemon = True so all the threads exit when the main thread(non-daemon) exits.


thread1 = threading.Thread(target=your_procedure, args = (arg_1, arg_2))    
try:
      thread1.setDaemon(True)  # very important
      thread1.start()
except (KeyboardInterrupt, SystemExit):
      cleanup_stop_thread();
      sys.exit()

When you want to kill the thread just use:

thread1.join(0)

참고URL : https://stackoverflow.com/questions/1635080/terminate-a-multi-thread-python-program

반응형