优雅地终止Python线程

时间:2011-06-15 14:45:26

标签: python multithreading

我正在尝试编写一个侦听套接字,stdin和从文件描述符读取的unix客户端程序。我将每个任务分配给一个单独的线程,并使用同步队列和信号量成功地与“主”应用程序通信。问题是,当我想关闭这些子线程时,它们都会在输入时阻塞。此外,线程无法在线程中注册信号处理程序,因为在Python中只允许执行主线程。

有什么建议吗?

3 个答案:

答案 0 :(得分:8)

没有好办法解决这个问题,特别是当线程阻塞时。

我有一个类似的问题(Python: How to terminate a blocking thread),我能够阻止我的线程的唯一方法是关闭底层连接。这导致阻塞引发和异常的线程然后允许我检查停止标志并关闭。

示例代码:

class Example(object):
   def __init__(self):
       self.stop = threading.Event()
       self.connection = Connection()
       self.mythread = Thread(target=self.dowork)
       self.mythread.start()     
   def dowork(self):

        while(not self.stop.is_set()):
             try:
                  blockingcall()        
             except CommunicationException:
                  pass
   def terminate():
       self.stop.set()
       self.connection.close()
       self.mythread.join()

需要注意的另一件事是通常阻塞操作通常会提供超时。如果您有这个选项,我会考虑使用它。我的最后一条评论是你总是可以将线程设置为deamonic,

来自pydoc:

  

线程可以标记为“守护程序线程”。这个标志的意义在于,当只剩下守护进程线程时,整个Python程序都会退出。初始值继承自创建线程。可以通过守护程序属性设置标志。

答案 1 :(得分:0)

  

此外,线程无法注册信号处理程序

杀死线程的信号可能很糟糕,特别是在C中,特别是如果你将内存分配给线程的一部分,因为当特定线程死亡时它不会被释放(因为它属于进程的堆)。 C中没有垃圾收集,所以如果指针超出范围,它就超出了范围,内存仍然被分配。所以只要小心那个 - 只有在C中这样做才能真正杀死所有线程并结束进程以便将内存交还给操作系统 - 例如在线程池中添加和删除线程会给你一个内存泄漏。

  

问题在于,当我想关闭这些子线程时,它们都会在输入时阻塞。

有趣的是,我最近一直在和同样的事情打架。该解决方案实际上不会在没有超时的情况下进行阻塞调用。所以,例如,你理想的是:

def threadfunc(running):

    while running:
        blockingcall(timeout=1)

从控制线程传递运行 - 我从未使用过线程,但我使用了多处理,实际上你需要传递一个Event()对象并检查is_set()。但是你问了设计模式,这是基本的想法。

然后,当您希望此线程结束时,运行:

running.clear()
mythread.join()

然后你的主线程应该允许你的客户端线程处理它的最后一个调用,并返回,整个程序很好地折叠。

如果您在没有超时的情况下进行阻止呼叫,该怎么办?使用异步选项,并且如果需要,可以休眠(如在调用任何方法暂停线程一段时间,这样你就不会旋转)。除此之外别无他法。

答案 2 :(得分:-1)

请参阅以下答案:

Python SocketServer
How to exit a multithreaded program?

基本上,不要在recv()上阻止select()超时检查套接字的可读性,并在select()超时时轮询退出标志。