终止多线程python程序

终止多线程python程序,python,multithreading,Python,Multithreading,如何使多线程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()

如何使多线程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()
导入线程
电流=0
类MyThread(threading.Thread):
定义初始值(自身,总计):
threading.Thread.\uuuuu init\uuuuuu(自)
self.total=总计
def停止(自):
self.\u线程\u停止()
def运行(自):
全球电流

当前将除主线程之外的每个线程都设置为守护进程(在2.6或更高版本中为
t.daemon=True
,在2.6或更低版本中为每个线程对象
t
在启动之前)。这样,当主线程接收到KeyboardInterrupt时,如果它没有捕捉到它或捕捉到它,但决定终止,整个进程将终止。看

编辑:刚刚看到OP的代码(不是最初发布的)和“它不工作”的声明,似乎我必须添加…:

当然,如果希望主线程保持响应(例如control-C),不要将其拖入阻塞调用中,例如
join
ing另一个线程——特别是不完全无用的阻塞调用,例如
join
ing守护进程threads。例如,只需将主线程中的最后一个循环更改为当前循环(完全没有,且具有破坏性):

更明智的做法是:

while threading.active_count() > 0:
    time.sleep(0.1)
如果main没有比让所有线程自行终止或接收control-C(或其他信号)更好的事情要做


当然,如果您希望线程不会突然终止(就像守护线程一样),还有许多其他可用的模式,除非它们也永远陷入无条件阻塞调用、死锁等的泥潭中;-)

主要有两种方法,一种是干净的,另一种是简单的

干净的方法是在主线程中捕获键盘中断,并设置后台线程可以检查的标志,以便它们知道退出;下面是一个简单/稍微混乱的版本,使用了全局变量:

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
混乱但简单的方法是捕获键盘中断并调用操作系统。_exit(),它会立即终止所有线程。

AWorker可能会对您有所帮助:

#!/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()
#/usr/bin/env python
导入系统,时间
从线程导入*
从集合导入deque
类工作者(对象):
def uuu init uuu(self,concurrent=1):
self.concurrent=concurrent
self.queue=deque([])
self.threads=[]
self.keep\u中断=False
def_保留_螺纹(自):
而len(self.threads)
我更愿意采用以下建议的代码:


我将t.joint.join(1)更改为t.join(1000)。实际秒数无关紧要,除非指定超时数,否则主线程将保持对Ctrl+C的响应。键盘上的except on中断使信号处理更加明确。

如果生成这样的线程-
myThread=thread(target=function)
-然后执行
myThread.start();myThread.join()
。当启动CTRL-C时,主线程不会退出,因为它正在等待阻塞
myThread.join()
调用。要解决此问题,只需在.join()调用上输入一个超时。超时时间可以任意长。如果你想让它无限期地等待,只需输入一个很长的超时,比如99999。执行myThread.daemon=True也是一种很好的做法,这样当主线程(非守护进程)退出时,所有线程都会退出。

您可以始终将线程设置为“守护进程”线程,如:

t.daemon = True
t.start()
每当主线程死亡时,所有线程都会随之死亡

如果要终止线程,只需使用:

thread1.join(0)

啊,你在做一个(无用的)阻塞调用——所以当然对control-C没有响应。解决方法很简单:如果你想保持响应,就不要做无用的阻塞调用。让我编辑我的答案来解释。@jack,您现在给出的代码立即终止(当然,因为主线程“从末尾掉下来”,这就结束了一切)。因此,它根本不可能接近您实际尝试的内容,而且很明显,您甚至没有尝试过您发布的代码;真的很难帮助你!请发布您尝试过的代码,并且确实重现了您遇到的问题,这样我就可以告诉您代码中的错误所在,而不是试图猜测您看不见的代码可能有哪些错误。@jack,正如我已经提到的,如果这是您的代码,那么您现在的主要错误是“主线”从末尾掉下来,“一切都结束了”. 请尝试我上面给出的代码:
在线程执行时。active\u count()>0:time.sleep(0.1)
--w
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.daemon = True
t.start()
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)