有什么办法可以杀死一个线程吗?
是否可以在不设置/检查任何标志/信号量/等的情况下终止正在运行的线程?
Is it possible to terminate a running thread without setting/checking any flags/semaphores/etc.?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
无论是在 Python 中还是在任何语言中,突然终止线程通常都是一种不好的模式。 考虑以下情况:
如果您负担得起(如果您正在管理自己的线程),处理此问题的好方法是使用 exit_request 标志,每个线程定期检查该标志以查看是否到了退出的时间。
例如:
在此代码中,当您希望线程退出时,您应该在线程上调用
stop()
,并使用join等待线程正确退出()
。 线程应定期检查停止标志。然而,在某些情况下,您确实需要终止线程。 一个例子是,当您正在包装一个忙于长时间调用的外部库时,并且您想要中断它。
以下代码允许(有一些限制)在 Python 线程中引发异常:(
基于 可杀死线程 作者:Tomer Filiba 关于
PyThreadState_SetAsyncExc
返回值的引用似乎来自 旧版本的 Python。)正如文档中所述,这不是灵丹妙药,因为如果线程在 Python 解释器之外忙,它不会抓住中断。
此代码的一个良好使用模式是让线程捕获特定异常并执行清理。 这样,您可以中断任务并仍然进行适当的清理。
It is generally a bad pattern to kill a thread abruptly, in Python, and in any language. Think of the following cases:
The nice way of handling this, if you can afford it (if you are managing your own threads), is to have an exit_request flag that each thread checks on a regular interval to see if it is time for it to exit.
For example:
In this code, you should call
stop()
on the thread when you want it to exit, and wait for the thread to exit properly usingjoin()
. The thread should check the stop flag at regular intervals.There are cases, however, when you really need to kill a thread. An example is when you are wrapping an external library that is busy for long calls, and you want to interrupt it.
The following code allows (with some restrictions) to raise an Exception in a Python thread:
(Based on Killable Threads by Tomer Filiba. The quote about the return value of
PyThreadState_SetAsyncExc
appears to be from an old version of Python.)As noted in the documentation, this is not a magic bullet because if the thread is busy outside the Python interpreter, it will not catch the interruption.
A good usage pattern of this code is to have the thread catch a specific exception and perform the cleanup. That way, you can interrupt a task and still have proper cleanup.
multiprocessing.Process
可以p.terminate()
在以下情况下我想杀死一个线程,但不想使用标志/锁/信号/信号量/事件/任何东西,我将线程提升为完整的进程。 对于只使用几个线程的代码来说,开销并没有那么糟糕。
例如,这可以方便地轻松终止执行阻塞 I/O 的帮助程序“线程”。
转换很简单:在相关代码中,将所有
threading.Thread
替换为multiprocessing.Process
并所有queue.Queue
与multiprocessing.Queue
并将所需的p.terminate()
调用添加到想要杀死其子进程的父进程p
请参阅有关
多处理
的 Python 文档。例子:
A
multiprocessing.Process
canp.terminate()
In the cases where I want to kill a thread, but do not want to use flags/locks/signals/semaphores/events/whatever, I promote the threads to full blown processes. For code that makes use of just a few threads the overhead is not that bad.
E.g. this comes in handy to easily terminate helper "threads" which execute blocking I/O
The conversion is trivial: In related code replace all
threading.Thread
withmultiprocessing.Process
and allqueue.Queue
withmultiprocessing.Queue
and add the required calls ofp.terminate()
to your parent process which wants to kill its childp
See the Python documentation for
multiprocessing
.Example:
没有官方 API 可以做到这一点,没有。
您需要使用平台 API 来终止线程,例如 pthread_kill 或 TerminateThread。 您可以通过 pythonwin 或 ctypes 访问此类 API。
请注意,这本质上是不安全的。 它可能会导致无法收集的垃圾(来自成为垃圾的堆栈帧的局部变量),并且如果被杀死的线程在被杀死时具有 GIL,则可能会导致死锁。
There is no official API to do that, no.
You need to use platform API to kill the thread, e.g. pthread_kill, or TerminateThread. You can access such API e.g. through pythonwin, or through ctypes.
Notice that this is inherently unsafe. It will likely lead to uncollectable garbage (from local variables of the stack frames that become garbage), and may lead to deadlocks, if the thread being killed has the GIL at the point when it is killed.
如果您试图终止整个程序,您可以将线程设置为“守护进程”。 请参阅
Thread.daemon
If you are trying to terminate the whole program you can set the thread as a "daemon". see
Thread.daemon
正如其他人提到的,规范是设置停止标志。 对于轻量级的东西(没有 Thread 的子类化,没有全局变量),lambda 回调是一个选项。 (请注意
if stop()
中的括号。)将
print()
替换为始终刷新的pr()
函数 (sys .stdout.flush()
) 可以提高 shell 输出的精度。(仅在Windows/Eclipse/Python3.3上测试)
As others have mentioned, the norm is to set a stop flag. For something lightweight (no subclassing of Thread, no global variable), a lambda callback is an option. (Note the parentheses in
if stop()
.)Replacing
print()
with apr()
function that always flushes (sys.stdout.flush()
) may improve the precision of the shell output.(Only tested on Windows/Eclipse/Python3.3)
在 Python 中,您根本无法直接终止线程。
如果您确实不需要线程(!),您可以做什么,而不是使用 threading包,就是使用
多处理包。 在这里,要终止进程,您可以简单地调用以下方法:
Python 将终止您的进程(在 Unix 上通过 SIGTERM 信号,而在 Windows 上通过
TerminateProcess()
调用)。 使用Queue或Pipe时注意使用它! (它可能会损坏队列/管道中的数据)请注意,
multiprocessing.Event
和multiprocessing.Semaphore
的工作方式与线程完全相同。分别是事件
和threading.Semaphore
。 事实上,第一个是后者的克隆。如果您确实需要使用线程,则无法直接杀死它。 然而,您可以做的是使用“守护线程”。 事实上,在Python中,一个线程可以被标记为守护进程:
当没有剩余的活动非守护线程时,主程序将退出。 换句话说,当你的主线程(当然是非守护线程)完成其操作时,即使仍有一些守护线程在工作,程序也会退出。
请注意,在调用
start()
方法之前,需要将线程设置为daemon
!当然,您可以而且应该使用
daemon
,甚至使用multiprocessing
。 在这里,当主进程退出时,它会尝试终止其所有守护进程子进程。最后,请注意
sys.exit()
和os.kill()
不是选择。In Python, you simply cannot kill a Thread directly.
If you do NOT really need to have a Thread (!), what you can do, instead of using the threading package , is to use the
multiprocessing package . Here, to kill a process, you can simply call the method:
Python will kill your process (on Unix through the SIGTERM signal, while on Windows through the
TerminateProcess()
call). Pay attention to use it while using a Queue or a Pipe! (it may corrupt the data in the Queue/Pipe)Note that the
multiprocessing.Event
and themultiprocessing.Semaphore
work exactly in the same way of thethreading.Event
and thethreading.Semaphore
respectively. In fact, the first ones are clones of the latters.If you REALLY need to use a Thread, there is no way to kill it directly. What you can do, however, is to use a "daemon thread". In fact, in Python, a Thread can be flagged as daemon:
The main program will exit when no alive non-daemon threads are left. In other words, when your main thread (which is, of course, a non-daemon thread) will finish its operations, the program will exit even if there are still some daemon threads working.
Note that it is necessary to set a Thread as
daemon
before thestart()
method is called!Of course you can, and should, use
daemon
even withmultiprocessing
. Here, when the main process exits, it attempts to terminate all of its daemonic child processes.Finally, please, note that
sys.exit()
andos.kill()
are not choices.这是基于 thread2 -- 可杀死线程 ActiveState 配方。
您需要调用
PyThreadState_SetAsyncExc()
< /a>,只能通过ctypes
模块。这仅在 Python 2.7.3 上进行了测试,但它可能适用于其他最近的 2.x 版本。
PyThreadState_SetAsyncExc()
仍然存在于 Python 3 中以实现向后兼容性(但我尚未测试它)。This is based on the thread2 -- killable threads ActiveState recipe.
You need to call
PyThreadState_SetAsyncExc()
, which is only available through thectypes
module.This has only been tested on Python 2.7.3, but it is likely to work with other recent 2.x releases.
PyThreadState_SetAsyncExc()
still exists in Python 3 for backwards compatibility (but I have not tested it).你永远不应该在不与线程合作的情况下强行杀死它。
终止线程会消除 try/finally 块设置的任何保证,因此您可能会保持锁锁定、文件打开等。
您唯一可以争论强制终止线程是个好主意的时候是快速终止程序,但绝不是单线程。
You should never forcibly kill a thread without cooperating with it.
Killing a thread removes any guarantees that try/finally blocks set up so you might leave locks locked, files open, etc.
The only time you can argue that forcibly killing threads is a good idea is to kill a program fast, but never single threads.
如果您显式调用
time.sleep()
作为线程的一部分(例如轮询某些外部服务),则对 Phillipe 方法的改进是在事件
中使用超时的wait()
方法,无论您在sleep()
的何处,例如:
然后运行它
使用
wait()
代替的优点>sleep() 并定期检查事件是您可以以更长的睡眠间隔进行编程,线程几乎立即停止(否则您将使用
sleep()
)并且在我看来,处理退出的代码要简单得多。If you are explicitly calling
time.sleep()
as part of your thread (say polling some external service), an improvement upon Phillipe's method is to use the timeout in theevent
'swait()
method wherever yousleep()
For example:
Then to run it
The advantage of using
wait()
instead ofsleep()
ing and regularly checking the event is that you can program in longer intervals of sleep, the thread is stopped almost immediately (when you would otherwise besleep()
ing) and in my opinion, the code for handling exit is significantly simpler.您可以通过将跟踪安装到将退出该线程的线程中来终止该线程。 请参阅附加链接了解一种可能的实现。
杀死Python 中的线程
You can kill a thread by installing trace into the thread that will exit the thread. See attached link for one possible implementation.
Kill a thread in Python
绝对可以实现
Thread.stop
方法,如以下示例代码所示:Thread3
类的代码运行速度似乎比Thread2 快约 33%类。
附录:
如果对 Python 的 C API 有足够的了解并使用
ctypes
模块,就可以编写一种更有效的方法来在需要时停止线程。 使用 sys.settrace 的问题是跟踪函数在每条指令之后运行。 如果在需要中止的线程上引发异步异常,则不会产生执行速度损失。 以下代码在这方面提供了一些灵活性:It is definitely possible to implement a
Thread.stop
method as shown in the following example code:The
Thread3
class appears to run code approximately 33% faster than theThread2
class.Addendum:
With sufficient knowledge of Python's C API and the use of the
ctypes
module, it is possible to write a far more efficient way of stopping a thread when desired. The problem with usingsys.settrace
is that the tracing function runs after each instruction. If an asynchronous exception is raised instead on the thread that needs to be aborted, no execution speed penalty is incurred. The following code provides some flexibility in this regard:如果你不杀死线程会更好。
一种方法可能是在线程循环中引入一个“try”块,并在您想要停止线程时抛出异常(例如,停止 for/while/... 的break/return/...)。
我已经在我的应用程序上使用了它并且它有效......
It is better if you don't kill a thread.
A way could be to introduce a "try" block into the thread's cycle and to throw an exception when you want to stop the thread (for example a break/return/... that stops your for/while/...).
I've used this on my app and it works...
我玩这个游戏已经太晚了,但我一直在努力解决一个类似的问题,以下内容似乎都可以解决这个问题非常适合我,并且让我在守护进程子线程退出时进行一些基本的线程状态检查和清理:
产量:
I'm way late to this game, but I've been wrestling with a similar question and the following appears to both resolve the issue perfectly for me AND lets me do some basic thread state checking and cleanup when the daemonized sub-thread exits:
Yields:
以下解决方法可用于终止线程:
这甚至可以用于从主线程终止线程,其代码是在另一个模块中编写的。 我们可以在该模块中声明一个全局变量,并使用它来终止该模块中生成的线程。
我通常用它来终止程序退出时的所有线程。 这可能不是终止线程的完美方法,但可能会有所帮助。
Following workaround can be used to kill a thread:
This can be used even for terminating threads, whose code is written in another module, from main thread. We can declare a global variable in that module and use it to terminate thread/s spawned in that module.
I usually use this to terminate all the threads at the program exit. This might not be the perfect way to terminate thread/s but could help.
这是另一种方法,但代码极其干净和简单,可在 2021 年的 Python 3.7 中运行:
改编自此处:https://www.geeksforgeeks.org/python- Different-ways-to-kill-a-thread/
Here's yet another way to do it, but with extremely clean and simple code, that works in Python 3.7 in 2021:
Adapted from here: https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
t 是您的
Thread
对象。阅读Python源代码(
Modules/threadmodule.c
和Python/thread_pthread.h
)你可以看到Thread.ident
是一个pthread_t
类型,因此您可以使用libpthread
在 python 中执行pthread
可以执行的任何操作。t is your
Thread
object.Read the python source (
Modules/threadmodule.c
andPython/thread_pthread.h
) you can see theThread.ident
is anpthread_t
type, so you can do anythingpthread
can do in python uselibpthread
.我想补充的一件事是,如果您阅读 threading lib Python,当您不希望线程突然结束时,建议避免使用“恶魔”线程,并使用 Paolo Rovelli 提到的标志。
来自官方文档:
我认为创建守护线程取决于您的应用程序,但一般来说(在我看来)最好避免杀死它们或使它们成为守护线程。 在多处理中,您可以使用 is_alive() 来检查进程状态并“终止”以完成它们(也可以避免 GIL 问题)。 但有时,当您在 Windows 中执行代码时,您会发现更多问题。
永远记住,如果你有“活动线程”,Python 解释器将运行等待它们。 (因为如果无关紧要的事情突然结束,这个守护进程可以帮助你)。
One thing I want to add is that if you read official documentation in threading lib Python, it's recommended to avoid use of "demonic" threads, when you don't want threads end abruptly, with the flag that Paolo Rovelli mentioned.
From official documentation:
I think that creating daemonic threads depends of your application, but in general (and in my opinion) it's better to avoid killing them or making them daemonic. In multiprocessing you can use
is_alive()
to check process status and "terminate" for finish them (Also you avoid GIL problems). But you can find more problems, sometimes, when you execute your code in Windows.And always remember that if you have "live threads", the Python interpreter will be running for wait them. (Because of this daemonic can help you if don't matter abruptly ends).
有一个为此目的构建的库,stopit。 尽管此处列出的一些相同注意事项仍然适用,但至少该库提供了一种常规的、可重复的技术来实现既定目标。
There is a library built for this purpose, stopit. Although some of the same cautions listed herein still apply, at least this library presents a regular, repeatable technique for achieving the stated goal.
只是为了建立 @SCB 的想法(这正是我所需要的),创建一个具有自定义函数的 KillableThread 子类:
当然,与 @SBC 一样,线程不会等待运行新循环来停止。 在此示例中,您将看到在“关于终止线程”之后立即打印“正在终止线程”消息,而不是再等待 4 秒让线程完成(因为我们已经休眠了 6 秒)。
KillableThread 构造函数中的第二个参数是您的自定义函数(此处为 print_msg)。 Args 参数是在此处调用函数 (("hello world")) 时将使用的参数。
Just to build up on @SCB's idea (which was exactly what I needed) to create a KillableThread subclass with a customized function:
Naturally, like with @SBC, the thread doesn't wait to run a new loop to stop. In this example, you would see the "Killing Thread" message printed right after the "About to kill thread" instead of waiting for 4 more seconds for the thread to complete (since we have slept for 6 seconds already).
Second argument in KillableThread constructor is your custom function (print_msg here). Args argument are the arguments that will be used when calling the function (("hello world")) here.
另一种方法是使用
signal.pthread_kill
< /a> 发送停止信号。结果
An alternative is to use
signal.pthread_kill
to send a stop signal.result
虽然它相当旧,这对于某些人来说可能是一个方便的解决方案:
因此,它允许“线程在另一个线程的上下文中引发异常”,这样,终止的线程可以处理终止而无需定期检查中止标志。
然而,根据其原始来源,这段代码存在一些问题。
While it's rather old, this might be a handy solution for some:
So, it allows a "thread to raise exceptions in the context of another thread" and in this way, the terminated thread can handle the termination without regularly checking an abort flag.
However, according to its original source, there are some issues with this code.
假设您想要拥有同一功能的多个线程,恕我直言,这是通过 id 停止一个的最简单的实现:
好处是,您可以拥有多个相同和不同的功能,并通过
停止它们functionname.stop
如果你只想让函数有一个线程,那么你不需要记住 id。 如果
doit.stop
> 就停止 0。Asuming, that you want to have multiple threads of the same function, this is IMHO the easiest implementation to stop one by id:
The nice thing is here, you can have multiple of same and different functions, and stop them all by
functionname.stop
If you want to have only one thread of the function then you don't need to remember the id. Just stop, if
doit.stop
> 0.正如 @Kozyarchuk 的答案中提到的,安装跟踪工作。 由于此答案不包含任何代码,因此这里是一个可立即使用的示例:
它在打印
1
和2
后停止。 不打印3
。As mentioned in @Kozyarchuk's answer, installing trace works. Since this answer contained no code, here is a working ready-to-use example:
It stops after having printed
1
and2
.3
is not printed.Python版本:3.8
使用守护线程来执行我们想要的事情,如果我们想要终止守护线程,我们只需让父线程退出,那么系统就会终止父线程创建的守护线程。
还支持协程和协程函数。
下面是ExitThread源代码
Python version: 3.8
Using daemon thread to execute what we wanted, if we want to daemon thread be terminated, all we need is making parent thread exit, then system will terminate daemon thread which parent thread created.
Also support coroutine and coroutine function.
below is ExitThread source code
如果您确实需要终止子任务的能力,请使用替代实现。
multiprocessing
和gevent
都支持不加区别地杀死“线程”。Python 的线程不支持取消。 想都别想。 您的代码很可能会死锁、损坏或泄漏内存,或者产生其他意外的“有趣的”难以调试的效果,这些效果很少发生且不确定。
If you really need the ability to kill a sub-task, use an alternate implementation.
multiprocessing
andgevent
both support indiscriminately killing a "thread".Python's threading does not support cancellation. Do not even try. Your code is very likely to deadlock, corrupt or leak memory, or have other unintended "interesting" hard-to-debug effects which happen rarely and nondeterministically.
Pieter Hintjens - ØMQ 项目的创始人之一 - 说,使用 ØMQ 和避免使用锁、互斥体、事件等同步原语,是编写多线程程序最明智、最安全的方法:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
这包括告诉子线程它应该取消其工作。 这可以通过为线程配备一个 ØMQ 套接字并在该套接字上轮询一条消息来表示它应该取消来完成。
该链接还提供了使用 ØMQ 的多线程 python 代码的示例。
Pieter Hintjens -- one of the founders of the ØMQ-project -- says, using ØMQ and avoiding synchronization primitives like locks, mutexes, events etc., is the sanest and securest way to write multi-threaded programs:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
This includes telling a child thread, that it should cancel its work. This would be done by equipping the thread with a ØMQ-socket and polling on that socket for a message saying that it should cancel.
The link also provides an example on multi-threaded python code with ØMQ.
这似乎适用于 Windows 7 上的 pywin32
This seems to work with pywin32 on windows 7
您可以在进程中执行命令,然后使用进程 ID 终止它。
我需要在两个线程之间同步,其中一个线程不会自行返回。
You can execute your command in a process and then kill it using the process id.
I needed to sync between two thread one of which doesn’t return by itself.
以下是如何做到这一点:
给它几秒钟,然后你的线程应该停止。 另请检查
thread._Thread__delete()
方法。为了方便起见,我建议使用
thread.quit()
方法。 例如,如果您的线程中有一个套接字,我建议您在套接字句柄类中创建一个quit()
方法,终止该套接字,然后运行一个thread._Thread__stop()
位于quit()
内部。Here's how to do it:
Give it a few seconds then your thread should be stopped. Check also the
thread._Thread__delete()
method.I'd recommend a
thread.quit()
method for convenience. For example if you have a socket in your thread, I'd recommend creating aquit()
method in your socket-handle class, terminate the socket, then run athread._Thread__stop()
inside of yourquit()
.使用 setDaemon(True) 启动子线程。
Start the sub thread with setDaemon(True).