web-dev-qa-db-ja.com

マルチスレッドを終了するpythonプログラム

マルチスレッドを作成する方法python Ctrl + Cキーイベントに対するプログラムの応答?

編集:コードは次のとおりです。

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
71
jack

メインスレッド以外のすべてのスレッドをデーモンにします(2.6以前の_t.daemon = True_、2.6以前のt.setDaemon(True)、すべてのスレッドオブジェクトtを開始する前に)。このように、メインスレッドがKeyboardInterruptを受信したときに、それをキャッチしないか、キャッチしたが、とにかく終了することにした場合、プロセス全体が終了します。 ドキュメント を参照してください。

edit:OPのコード(最初に投稿されたものではない)と「機能しない」という主張を見て、追加する必要があるようです。 ..:

もちろん、メインスレッドの応答性を維持したい場合(control-Cなど)、別のスレッドのjoiningなどのブロッキング呼び出しに取り込んではいけません。特に完全ではありませんuselessjoiningdaemonスレッドなどの呼び出しをブロックします。たとえば、メインスレッドの最後のループを現在のものから変更するだけです(完全かつ破損しています)。

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

より賢明なものに:

_while threading.active_count() > 0:
    time.sleep(0.1)
_

メインがすべてのスレッドを自分で終了させるか、control-C(または他の信号)を受信するよりも良い方法がない場合。

もちろん、(デーモンスレッドがそうであるように)スレッドを突然終了させたくない場合は、他の多くの使用可能なパターンがあります-theyも無条件に永久に搾取されない限り-呼び出し、デッドロックなどのブロック;-)。

90
Alex Martelli

主に2つの方法があります。1つはクリーンで、もう1つは簡単です。

クリーンな方法は、メインスレッドでKeyboardInterruptをキャッチし、バックグラウンドスレッドがチェックできるフラグを設定して、終了することがわかるようにすることです。以下は、グローバルを使用した単純な/やや乱雑なバージョンです。

exitapp = False
if __== '__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()を呼び出すことです。これにより、すべてのスレッドがすぐに終了します。

16
Walter Mundt

Workerは役に立つかもしれません:

#!/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()
5
Mark Ma

スレッドはいつでも「デーモン」スレッドに設定できます。

t.daemon = True
t.start()

そして、メインスレッドが死ぬたびに、すべてのスレッドはそれとともに死にます。

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

4
Ehsanjs

このブログ投稿 で提案されているコードを使用したいです。

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

私が変更したのは、t.joinfromt.join(1)t.join(1000)実際の秒数は重要ではありません。タイムアウト値を指定しない限り、メインスレッドはCtrl + Cに対する応答性を維持します。 KeyboardInterruptを除くと、信号処理がより明確になります。

4
Konrad Reiche

myThread = Thread(target = function)-のようなスレッドを生成し、myThread.start(); myThread.join()を実行した場合。 CTRL-Cが開始されると、メインスレッドはそのmyThread.join()呼び出しを待機しているため終了しません。これを修正するには、単に.join()呼び出しにタイムアウトを設定します。タイムアウトはあなたが望む限り長くすることができます。無限に待機させたい場合は、99999のような非常に長いタイムアウトを設定するだけです。myThread.daemon = Trueそのため、メインスレッド(非デーモン)が終了すると、すべてのスレッドが終了します。

1
Milean
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()

スレッドを強制終了したい場合は、次を使用します。

thread1.join(0)
1
Charles P.