multithreading - python有什么办法杀一个进程?

  显示原文与译文双语对照的内容

是否可以在不设置/检查任何 flags/semaphores/etc.?的情况下终止正在运行的线程

时间:

在 python 和任何语言中突然终止线程通常是一个糟糕的模式。 请考虑以下情况:

  • 线程持有必须正确关闭的关键资源
  • 线程创建了几个必须同时被杀死的线程。

于他去找exit,相关不错的办法来处理这个如果你能够负担( 如果你正在管理自己的线程) 固定间隔上是让元exit_request标志,每个线程会检查两个结构来看它是否否定

例如:


import threading

class StoppableThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
 regularly for the stopped() condition."""

 def __init__(self):
 super(StoppableThread, self).__init__()
 self._stop = threading.Event()

 def stop(self):
 self._stop.set()

 def stopped(self):
 return self._stop.isSet()

在这里代码中,你应该在线程退出时调用 stop(),并等待线程使用 join() 正确退出。 线程应该定期检查停止标志。

但是有时候你真的需要杀死一个线程。 例如当你正在包装一个忙于长时间调用的外部库时,你想中断它。

下面的代码允许( 有一些限制) 在 python 线程中引发异常:


def _async_raise(tid, exctype):
 '''Raises an exception in the threads with id tid'''
 if not inspect.isclass(exctype):
 raise TypeError("Only types can be raised (not instances)")
 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
 ctypes.py_object(exctype))
 if res == 0:
 raise ValueError("invalid thread id")
 elif res!= 1:
 #"if it returns a number greater than one, you're in trouble,
 # and you should call it again with exc=NULL to revert the effect"
 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
 raise SystemError("PyThreadState_SetAsyncExc failed")

class ThreadWithExc(threading.Thread):
 '''A thread class that supports raising exception in the thread from
 another thread.
 '''
 def _get_my_tid(self):
"""determines this (self's) thread id

 CAREFUL : this function is executed in the context of the caller
 thread, to get the identity of the thread represented by this
 instance.
"""
 if not self.isAlive():
 raise threading.ThreadError("the thread is not active")

 # do we have it cached?
 if hasattr(self,"_thread_id"):
 return self._thread_id

 # no, look for it in the _active dict
 for tid, tobj in threading._active.items():
 if tobj is self:
 self._thread_id = tid
 return tid

 # TODO: in python 2.6, there's a simpler way to do : self.ident

 raise AssertionError("could not determine the thread's id")

 def raiseExc(self, exctype):
"""Raises the given exception type in the context of this thread.

 If the thread is busy in a system call (time.sleep(),
 socket.accept(),.. .), the exception is simply ignored.

 If you are sure that your exception should terminate the thread,
 one way to ensure that it works is:

 t = ThreadWithExc(.. . )
. . .
 t.raiseExc( SomeException )
 while t.isAlive():
 time.sleep( 0.1 )
 t.raiseExc( SomeException )

 If the exception is to be caught by the thread, you need a way to
 check that your thread has caught it.

 CAREFUL : this function is executed in the context of the
 caller thread, to raise an excpetion in the context of the
 thread represented by this instance.
"""
 _async_raise( self._get_my_tid(), exctype )

就像文档中提到的,这不是一个魔术项目,因为如果线程在 python 解释器之外忙,它将不会捕获中断。

这里代码的一个好用法是让线程捕获一个特定异常并执行清理。 这样,你就可以中断一个任务并仍然有适当的清理。

没有官方的API可以做到这点,没有。

你需要使用平台API来终止线程,比如 pthread_kill或者 TerminateThread 。 你可以接触此类API通过 PythonWin 比如,或者通过 ctypes 。

注意这本质上是不安全的。 它可能会导致uncollectable垃圾( 从堆栈帧的局部变量变成垃圾),并可能导致死锁,如果被杀死的线程在被杀死的时候有 GIL 。

如果你试图终止整个程序,你可以将线程设置为"守护进程"。 参见 Thread.daemon web

multiprocessing.Process 可以 p.terminate()

在我想要杀死线程但不想使用 flags/locks/signals/semaphores/events/whatever,的情况下,我将线程提升到完全吹出进程。 对于使用少量线程的代码,开销不是那么严重。

E.g 。方便地终止 helper"线程",它执行阻塞i/o

中的转换非常容易:相关代码替换所有与 multiprocessing.Processthreading.Thread 和所有与 multiprocessing.Queuequeue.Queuep.terminate() 到你的父进程和添加所需的调用,它想要杀死其子 p

python doc

没有与它协作的情况下,你绝不应该强行杀死一个线程。

杀死线程会删除任何尝试/finally块设置的保证,这样你可能会锁定锁,打开文件等。

你唯一可以争辩的是强行杀死线程是一个好主意,就是快速终止一个程序,但绝不是单个线程。

你最好不要杀死一个线程。 在我的应用,然后它的工作原理。., 一个方法有可能引入一个"试用"块插入循环的线程又要引发异常当你想停止该线程( 例如一个 break/return/...,停止你的for/while/...). 我已经使用过这个,

这是基于 http://code.activestate.com/recipes/496960-thread2-killable-threads/

你需要调用 PyThreadState_SetasyncExc(),,它只能通过ctypes使用。

这只在 python 2.7.3上测试过,但它可能与其他最近的2.x 版本一起使用。


import ctypes

def terminate_thread(thread):
"""Terminates a python thread from another thread.

 :param thread: a threading.Thread instance
"""
 if not thread.isAlive():
 return

 exc = ctypes.py_object(SystemExit)
 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
 ctypes.c_long(thread.ident), exc)
 if res == 0:
 raise ValueError("nonexistent thread id")
 elif res> 1:
 #"""if it returns a number greater than one, you're in trouble,
 # and you should call it again with exc=NULL to revert the effect"""
 ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
 raise SystemError("PyThreadState_SetAsyncExc failed")

以下是操作方法:


from threading import *

...

for thread in enumerate():
 if thread.isAlive():
 try:
 thread._Thread__stop()
 except:
 print(str(thread.getName()) + ' could not be terminated'))

几秒钟后你的线程就会被停止。 检查 thread._Thread__delete() 方法。

我建议使用 thread.quit() 方法来方便。 例如如果你有一个插座,在你的线程,我建议创建一个在你的socket-handle quit() 方法类,终止套接字,然后运行一个 thread._Thread__stop() 进去你的quit()

在 python 中,你不能直接杀死一个线程。

如果你并不真正需要有一个线程( ),你可以做什么,而不是利用( http://docs.python.org/2/library/threading.html ) 线程包,是使用了多处理 包( http://docs.python.org/2/library/multiprocessing.html ) 。 在这里,要杀死一个进程,你可以简单地调用该方法:


yourProcess.terminate() # kill the process!

python 将杀死你的进程( 在Unix上通过SIGTERM信号,而在 Windows 通过 TerminateProcess() 调用) 。 使用队列或者管道时注意使用 ! ( 可能会损坏队列/管道中的数据)

请注意,multiprocessing.Event 和 multiprocessing.Semaphore的工作原理完全以同样的方式 threading.Event 和 threading.Semaphore 分别。 事实上,第一种是latters的克隆。

如果你真的需要使用一个线程,就不能直接杀死它。 但是,你可以做的是使用 "守护进程线程" 。 事实上,在 python 中,一个线程可以被标记为守护进程:


yourThread.daemon = True # set the Thread as a"daemon thread"

当没有剩余的non-daemon线程时主程序将退出。 换句话说,当你的主线程( 当然,这是一个non-daemon线程) 完成它的操作时,即使仍然有一些守护线程工作,程序也会退出。

请注意,之前,有必要设置一个线程为后台程序 start() 方法被调用 !

多处理, 当然你可以。也应该使用守护 even. 在这里,当主进程退出时,它试图终止它的所有后台进程。

最后,求你了,请注意,sys.exit() 和 os.kill() 不选择。


 from ctypes import *
 pthread = cdll.LoadLibrary("libpthread-2.15.so")
 pthread.pthread_cancel(c_ulong(t.ident))

t 是你 Thread 对象。

你可以看到 python 源( Modules/threadmodule.cPython/thread_pthread.h ) 你可以看到 Thread.ident 是一个 pthread_t 类型,所以你可以做任何 pthread,可以在 python 中使用 libpthread

...