python线程在终止后继续

时间:2015-01-16 15:20:54

标签: python multithreading terminate

我试图终止一个工作线程超过一定时间。我面临的问题是线程在终止后仍然继续。我检查它是由isAlive终止并实际上完全删除引用 - 但线程继续。

附件是代码片段和实际输出与我期待的结果。我删除了我的实际工作代码并将其替换为睡眠以轻松演示并将工作线程设置为10秒,并且线程完成的时间保护为5秒。

由于

from threading import Thread, Timer
import Queue
from time import strftime, gmtime, sleep

class test(object):

    worker_thread = None
    q = Queue.Queue()

    def terminate_test(self):

        if self.worker_thread.isAlive():
            print 'stopping', self.worker_thread.getName(), strftime("%Y-%m-%d %H:%M:%S", gmtime())
            self.worker_thread._Thread__stop()
            self.worker_thread.join()
            print "Thread alive?", self.worker_thread.getName(), self.worker_thread.isAlive()
            del self.worker_thread
            print 'stopped'
    #            self._testq.task_done()

        else:
            print 'worker finished before stopping', strftime("%Y-%m-%d %H:%M:%S", gmtime())    

    def worker(self, item):
        k = item.keys()[0]
        v = item.values()[0]
        print 'starting', k, strftime("%Y-%m-%d %H:%M:%S", gmtime())
        print 'sleeping', v, strftime("%Y-%m-%d %H:%M:%S", gmtime())
        sleep(v)
        print "waking up", k,v, strftime("%Y-%m-%d %H:%M:%S", gmtime())
        self.q.task_done()
        self.test_terminate_thread.cancel()

    def start(self):
        source = [{'test a':10},{'test b':10},{'test c':10},{'test d':10}]
        for item in source:
            self.q.put(item)

        while not self.q.empty():
            item = self.q.get()
            self.worker_thread = Thread(target=self.worker, args=(item,))
            self.worker_thread.setName('test_thread %s' % item.keys()[0])

            self.test_terminate_thread = Timer(5, self.terminate_test)
            self.test_terminate_thread.setName("Test_terminate_thread")

            self.worker_thread.start()
            self.test_terminate_thread.start()

            self.worker_thread.join()    
            self.test_terminate_thread.join()

        print "joining Q", strftime("%Y-%m-%d %H:%M:%S", gmtime())        
        self.q.join()       

if __name__ == "__main__":
    test().start()

实际输出:(我不期待醒来的线路)

starting test a 2015-01-16 15:07:07
sleeping 10 2015-01-16 15:07:07
stopping test_thread test a 2015-01-16 15:07:12
Thread alive? test_thread test a False
stopped
starting test b 2015-01-16 15:07:12
sleeping 10 2015-01-16 15:07:12
waking up test a 10 2015-01-16 15:07:17
waking up test b 10 2015-01-16 15:07:22
starting test c 2015-01-16 15:07:22
sleeping 10 2015-01-16 15:07:22
stopping test_thread test c 2015-01-16 15:07:27
Thread alive? test_thread test c False
stopped
starting test d 2015-01-16 15:07:27
sleeping 10 2015-01-16 15:07:27
stopping test_thread test d 2015-01-16 15:07:32
Thread alive? test_thread test d False
stopped
joining Q 2015-01-16 15:07:32
waking up test c 10 2015-01-16 15:07:32
waking up test d 10 2015-01-16 15:07:37

我的期待

starting test a 2015-01-16 15:07:07
sleeping 10 2015-01-16 15:07:07
stopping test_thread test a 2015-01-16 15:07:12
Thread alive? test_thread test a False
stopped
starting test b 2015-01-16 15:07:12
sleeping 10 2015-01-16 15:07:12
starting test c 2015-01-16 15:07:22
sleeping 10 2015-01-16 15:07:22
stopping test_thread test c 2015-01-16 15:07:27
Thread alive? test_thread test c False
stopped
starting test d 2015-01-16 15:07:27
sleeping 10 2015-01-16 15:07:27
stopping test_thread test d 2015-01-16 15:07:32
Thread alive? test_thread test d False
stopped
joining Q 2015-01-16 15:07:32

1 个答案:

答案 0 :(得分:0)

您正在调用的_Thread__stop()函数实际上并未终止线程。这是一个内部方法,当线程的run方法结束时,它会被Python调用 - 这意味着只有在实际 停止的线程后才会调用它。实际上它只是将__stopped属性设置为True并通知在线程上等待它们可以继续的任何内容:

def __stop(self):
    # DummyThreads delete self.__block, but they have no waiters to
    # notify anyway (join() is forbidden on them).
    if not hasattr(self, '_Thread__block'):
        return
    self.__block.acquire()
    self.__stopped = True
    self.__block.notify_all()
    self.__block.release()

此外,is_alive() / isAlive()方法仅检查__stopped标志,它实际上并未验证run方法是否已完成,因为它假定为{{ 1}}只有在那是真的时才会被设置。

通常,中止线程的正确方法是让它以某种方式与主线程协同工作 - 比如让主线程设置__stopped以指示其中止的时间,工人偶尔检查。具体而言,哪种方法最适合您取决于您​​的具体用例。

以下是您可以更改示例以使用threading.Event的方法:

Event

输出:

def terminate_test(self, event):

    if self.worker_thread.isAlive():
        print 'stopping', self.worker_thread.getName(), strftime("%Y-%m-%d %H:%M:%S", gmtime())
        event.set()
        self.worker_thread.join()
        print "Thread alive?", self.worker_thread.getName(), self.worker_thread.isAlive()
        del self.worker_thread
        print 'stopped'

    else:
        print 'worker finished before stopping', strftime("%Y-%m-%d %H:%M:%S", gmtime())    

def worker(self, item, event):
    k = item.keys()[0]
    v = item.values()[0]
    print 'starting', k, strftime("%Y-%m-%d %H:%M:%S", gmtime())
    print 'sleeping', v, strftime("%Y-%m-%d %H:%M:%S", gmtime())
    if event.wait(v):
        return
    print "waking up", k,v, strftime("%Y-%m-%d %H:%M:%S", gmtime())
    self.q.task_done()
    self.test_terminate_thread.cancel()

def start(self):
    source = [{'test a':10},{'test b':10},{'test c':10},{'test d':10}]
    for item in source:
        self.q.put(item)

    while not self.q.empty():
        item = self.q.get()
        e = Event()
        self.worker_thread = Thread(target=self.worker, args=(item, e))
        self.worker_thread.setName('test_thread %s' % item.keys()[0])

        self.test_terminate_thread = Timer(5, self.terminate_test, args=(e,))
        self.test_terminate_thread.setName("Test_terminate_thread")