有什么方法可以终止线程吗?
- 2024-11-18 08:41:00
- admin 原创
- 12
问题描述:
是否可以在不设置/检查任何标志/信号量/等的情况下终止正在运行的线程?
解决方案 1:
无论是在 Python 中还是在任何语言中,突然终止线程通常都是一个糟糕的模式。想想以下情况:
该线程正在持有一个必须正确关闭的关键资源
该线程创建了几个其他线程,也必须将其终止。
如果您能够负担得起(如果您正在管理自己的线程),处理此问题的最佳方法是使用 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, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop_event = threading.Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
在此代码中,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(ctypes.c_long(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(ctypes.c_long(tid), None)
raise SystemError("PyThreadState_SetAsyncExc failed")
class ThreadWithExc(threading.Thread):
'''A thread class that supports raising an 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.is_alive(): # Note: self.isAlive() on older version of Python
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 raise_exc(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.raise_exc( SomeException )
while t.isAlive():
time.sleep( 0.1 )
t.raise_exc( 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 exception in the context of the
thread represented by this instance.
"""
_async_raise( self._get_my_tid(), exctype )
(基于Tomer Filiba 编写的Killable Threads。关于 返回值的引用PyThreadState_SetAsyncExc
似乎来自旧版本的 Python。)
正如文档中所述,这不是什么灵丹妙药,因为如果线程在 Python 解释器之外很忙,它将无法捕获中断。
此代码的一个良好使用模式是让线程捕获特定异常并执行清理。这样,您可以中断任务并仍进行适当的清理。
解决方案 2:
一个multiprocessing.Process
罐子p.terminate()
如果我想终止某个线程,但又不想使用标志/锁/信号/信号量/事件/等等,我会将线程提升为完全成熟的进程。对于只使用几个线程的代码来说,开销并不大。
例如,这可以方便地终止执行阻塞 I/O 的辅助“线程”。
转换很简单:在相关代码中,将所有替换threading.Thread
为multiprocessing.Process
,并将所有替换queue.Queue
为multiprocessing.Queue
,并将所需的调用添加p.terminate()
到想要终止其子进程的父进程中p
请参阅Python 文档multiprocessing
。
例子:
import multiprocessing
proc = multiprocessing.Process(target=your_proc_function, args=())
proc.start()
# Terminate the process
proc.terminate() # sends a SIGTERM
解决方案 3:
没有官方 API 可以做到这一点,没有。
您需要使用平台 API 来终止线程,例如 pthread_kill 或 TerminateThread。您可以通过 pythonwin 或 ctypes 访问此类 API。
请注意,这本质上是不安全的。这可能会导致无法收集的垃圾(来自堆栈框架的局部变量,这些变量会变成垃圾),并且如果被终止的线程在被终止时具有 GIL,则可能导致死锁。
解决方案 4:
如果你试图终止整个程序,你可以将线程设置为“守护进程”。参见Thread.daemon
解决方案 5:
正如其他人提到的,标准是设置停止标志。对于轻量级的东西(没有线程子类,没有全局变量),lambda 回调是一个选项。(请注意if stop()
. 中的括号)
import threading
import time
def do_work(id, stop):
print("I am thread", id)
while True:
print("I am thread {} doing something".format(id))
if stop():
print(" Exiting loop.")
break
print("Thread {}, signing off".format(id))
def main():
stop_threads = False
workers = []
for id in range(0,3):
tmp = threading.Thread(target=do_work, args=(id, lambda: stop_threads))
workers.append(tmp)
tmp.start()
time.sleep(3)
print('main: done sleeping; time to stop the threads.')
stop_threads = True
for worker in workers:
worker.join()
print('Finis.')
if __name__ == '__main__':
main()
print()
用pr()
始终刷新 () 的函数进行替换sys.stdout.flush()
可能会提高 shell 输出的精度。
(仅在 Windows/Eclipse/Python3.3 上测试)
解决方案 6:
在 Python 中,你根本无法直接终止线程。
如果你真的不需要线程(!),你可以使用多处理包,而不是使用
线程包。在这里,要终止进程,你只需调用该方法:
your_process.terminate() # kill the process!
Python 将终止您的进程(在 Unix 上通过 SIGTERM 信号,而在 Windows 上通过TerminateProcess()
调用)。请注意在使用队列或管道时使用它!(它可能会损坏队列/管道中的数据)
请注意,multiprocessing.Event
和 的multiprocessing.Semaphore
工作方式与threading.Event
和threading.Semaphore
完全相同。事实上,前者是后者的克隆。
如果你确实需要使用线程,没有办法直接杀死它。不过,你可以使用“守护线程”。事实上,在 Python 中,线程可以被标记为守护线程:
your_thread.daemon = True # set the Thread as a "daemon thread"
当没有剩余的非守护线程时,主程序将退出。换句话说,当你的主线程(当然是非守护线程)完成其操作时,即使仍有一些守护线程在运行,程序也会退出。
注意,在调用daemon
该方法之前必须设置一个线程!start()
当然,你可以并且应该将daemon
even 与 一起使用multiprocessing
。在这里,当主进程退出时,它会尝试终止其所有守护子进程。
最后,请注意sys.exit()
和os.kill()
不是选择。
解决方案 7:
这是基于线程2——可杀死线程的ActiveState配方。
您需要调用PyThreadState_SetAsyncExc()
,该功能仅通过ctypes
模块可用。
这仅在 Python 2.7.3 上进行了测试,但它可能与其他最近的 2.x 版本兼容。PyThreadState_SetAsyncExc()
在 Python 3 中仍然存在以实现向后兼容(但我没有测试过)。
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")
解决方案 8:
你绝不应该在没有得到配合的情况下强行终止一个线程。
终止线程会删除 try/finally 块设置的所有保证,因此您可能会使锁保持锁定状态、文件保持打开状态等。
唯一可以争辩说强制终止线程是一个好主意的情况是快速终止一个程序,但绝不会终止单个线程。
解决方案 9:
如果你明确地作为线程的一部分进行调用(比如轮询一些外部服务),那么对 Phillipe 方法的一个改进就是在方法time.sleep()
中使用超时,无论你在哪里event
`wait()`sleep()
例如:
import threading
class KillableThread(threading.Thread):
def __init__(self, sleep_interval=1):
super().__init__()
self._kill = threading.Event()
self._interval = sleep_interval
def run(self):
while True:
print("Do Something")
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
然后运行它
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
wait()
使用而不是ing 并定期检查事件的优点sleep()
是,您可以在更长的睡眠间隔内进行编程,线程几乎立即停止(当您原本sleep()
ing 时),并且在我看来,处理退出的代码明显简单得多。
解决方案 10:
您可以通过在将退出线程的线程中安装跟踪来终止线程。请参阅附件链接了解一种可能的实现。
在 Python 中终止一个线程
解决方案 11:
绝对可以实现Thread.stop
如以下示例代码所示的方法:
import sys
import threading
import time
class StopThread(StopIteration):
pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
###############################################################################
def main():
test1 = Thread2(target=printer)
test1.start()
time.sleep(1)
test1.stop()
test1.join()
test2 = Thread2(target=speed_test)
test2.start()
time.sleep(1)
test2.stop()
test2.join()
test3 = Thread3(target=speed_test)
test3.start()
time.sleep(1)
test3.stop()
test3.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
def speed_test(count=0):
try:
while True:
count += 1
except StopThread:
print('Count =', count)
if __name__ == '__main__':
main()
该类Thread3
运行代码的速度似乎比该类快约 33% Thread2
。
附录:
有了足够的 Python C API 知识和ctypes
模块的使用知识,就可以编写一种更有效的方法来在需要时停止线程。使用的问题sys.settrace
在于跟踪函数在每条指令之后运行。如果在需要中止的线程上引发异步异常,则不会产生执行速度损失。以下代码在这方面提供了一些灵活性:
#! /usr/bin/env python3
import _thread
import ctypes as _ctypes
import threading as _threading
_PyThreadState_SetAsyncExc = _ctypes.pythonapi.PyThreadState_SetAsyncExc
# noinspection SpellCheckingInspection
_PyThreadState_SetAsyncExc.argtypes = _ctypes.c_ulong, _ctypes.py_object
_PyThreadState_SetAsyncExc.restype = _ctypes.c_int
# noinspection PyUnreachableCode
if __debug__:
# noinspection PyShadowingBuiltins
def _set_async_exc(id, exc):
if not isinstance(id, int):
raise TypeError(f'{id!r} not an int instance')
if not isinstance(exc, type):
raise TypeError(f'{exc!r} not a type instance')
if not issubclass(exc, BaseException):
raise SystemError(f'{exc!r} not a BaseException subclass')
return _PyThreadState_SetAsyncExc(id, exc)
else:
_set_async_exc = _PyThreadState_SetAsyncExc
# noinspection PyShadowingBuiltins
def set_async_exc(id, exc, *args):
if args:
class StateInfo(exc):
def __init__(self):
super().__init__(*args)
return _set_async_exc(id, StateInfo)
return _set_async_exc(id, exc)
def interrupt(ident=None):
if ident is None:
_thread.interrupt_main()
else:
set_async_exc(ident, KeyboardInterrupt)
# noinspection PyShadowingBuiltins
def exit(ident=None):
if ident is None:
_thread.exit()
else:
set_async_exc(ident, SystemExit)
class ThreadAbortException(SystemExit):
pass
class Thread(_threading.Thread):
def set_async_exc(self, exc, *args):
return set_async_exc(self.ident, exc, *args)
def interrupt(self):
self.set_async_exc(KeyboardInterrupt)
def exit(self):
self.set_async_exc(SystemExit)
def abort(self, *args):
self.set_async_exc(ThreadAbortException, *args)
解决方案 12:
最好不要终止线程。一种方法是将“try”块引入线程循环,并在您想要停止线程时抛出异常(例如,break/return/... 会停止 for/while/...)。我在我的应用程序上使用过这种方法,效果很好...
解决方案 13:
我参加这个游戏已经很晚了,但是我一直在努力解决类似的问题,下面的方法似乎可以完美地解决我的问题,并且让我在守护进程的子线程退出时进行一些基本的线程状态检查和清理:
import threading
import time
import atexit
def do_work():
i = 0
@atexit.register
def goodbye():
print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
(i, threading.currentThread().ident))
while True:
print i
i += 1
time.sleep(1)
t = threading.Thread(target=do_work)
t.daemon = True
t.start()
def after_timeout():
print "KILL MAIN THREAD: %s" % threading.currentThread().ident
raise SystemExit
threading.Timer(2, after_timeout).start()
产量:
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
解决方案 14:
可以使用以下解决方法来终止线程:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
这甚至可以用于从主线程终止在另一个模块中编写的代码的线程。我们可以在该模块中声明一个全局变量,并使用它来终止在该模块中生成的线程。
我通常使用它在程序退出时终止所有线程。这可能不是终止线程的完美方法,但可能会有所帮助。
解决方案 15:
这是另一种方法,但代码非常干净和简单,可以在 2021 年的 Python 3.7 中运行:
import ctypes
def kill_thread(thread):
"""
thread: a threading.Thread object
"""
thread_id = thread.ident
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
改编自此处: https: //www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
解决方案 16:
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))
这是你的Thread
目标。
阅读 python 源代码(Modules/threadmodule.c
和Python/thread_pthread.h
)你可以看到Thread.ident
是一种pthread_t
类型,因此你可以pthread
使用 做任何可以在 python 中做的事情libpthread
。
解决方案 17:
我想补充一点,如果你阅读了Python 线程库的官方文档,建议避免使用“恶魔”线程,当你不希望线程突然结束时,请使用 Paolo Rovelli提到的标志。
来自官方文档:
守护线程在关闭时会突然停止。它们的资源(如打开的文件、数据库事务等)可能无法正确释放。如果您希望线程正常停止,请将它们设为非守护线程并使用合适的信号机制(如事件)。
我认为创建守护线程取决于您的应用程序,但一般来说(在我看来),最好避免杀死它们或使它们成为守护线程。在多处理中,您可以使用它is_alive()
来检查进程状态并“终止”以完成它们(还可以避免 GIL 问题)。但有时,当您在 Windows 中执行代码时,您会发现更多问题。
并且始终记住,如果您有“活动线程”,Python 解释器将运行并等待它们。(因为这个守护进程可以在事情突然结束时为您提供帮助)。
解决方案 18:
有一个为此目的而构建的库,stopit。尽管此处列出的一些注意事项仍然适用,但至少这个库提供了一种常规的、可重复的技术来实现所述目标。
解决方案 19:
只是为了建立@SCB 的想法(这正是我所需要的)来创建一个具有自定义功能的 KillableThread 子类:
from threading import Thread, Event
class KillableThread(Thread):
def __init__(self, sleep_interval=1, target=None, name=None, args=(), kwargs={}):
super().__init__(None, target, name, args, kwargs)
self._kill = Event()
self._interval = sleep_interval
print(self._target)
def run(self):
while True:
# Call custom function with arguments
self._target(*self._args)
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
if __name__ == '__main__':
def print_msg(msg):
print(msg)
t = KillableThread(10, print_msg, args=("hello world"))
t.start()
time.sleep(6)
print("About to kill thread")
t.kill()
当然,与 @SBC 一样,线程不会等待运行新循环而停止。在此示例中,您会看到在“即将终止线程”之后立即打印“终止线程”消息,而不是等待线程完成 4 秒钟(因为我们已经休眠了 6 秒钟)。
KillableThread 构造函数中的第二个参数是您的自定义函数(此处为 print_msg)。Args 参数是调用此处的函数 ((“hello world”)) 时将使用的参数。
解决方案 20:
另一种方法是使用signal.pthread_kill
发送停止信号。
from signal import pthread_kill, SIGTSTP
from threading import Thread
from itertools import count
from time import sleep
def target():
for num in count():
print(num)
sleep(1)
thread = Thread(target=target)
thread.start()
sleep(5)
pthread_kill(thread.ident, SIGTSTP)
结果
0
1
2
3
4
[14]+ Stopped
解决方案 21:
虽然它相当老旧,但对于某些人来说这可能是一个方便的解决方案:
扩展线程模块功能的一个小模块——允许一个线程在另一个线程的上下文中引发异常。通过引发
SystemExit
,您最终可以终止 python 线程。
import threading
import ctypes
def _async_raise(tid, excobj):
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
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(tid, 0)
raise SystemError("PyThreadState_SetAsyncExc failed")
class Thread(threading.Thread):
def raise_exc(self, excobj):
assert self.isAlive(), "thread must be started"
for tid, tobj in threading._active.items():
if tobj is self:
_async_raise(tid, excobj)
return
# the thread was alive when we entered the loop, but was not found
# in the dict, hence it must have been already terminated. should we raise
# an exception here? silently ignore?
def terminate(self):
# must raise the SystemExit type, instead of a SystemExit() instance
# due to a bug in PyThreadState_SetAsyncExc
self.raise_exc(SystemExit)
因此,它允许“线程在另一个线程的上下文中引发异常”,这样,终止的线程可以处理终止而无需定期检查中止标志。
然而,根据其原始来源,该代码存在一些问题。
只有在执行 Python 字节码时才会引发异常。如果您的线程调用本机/内置阻塞函数,则只有在执行返回 Python 代码时才会引发异常。
+ 如果内置函数内部调用 PyErr_Clear(),则也会出现问题,这将有效地取消您的待处理异常。您可以尝试再次引发它。
只有异常类型才能安全地引发。异常实例很可能导致意外行为,因此受到限制。
+ 例如:t1.raise_exc(TypeError)而不是t1.raise_exc(TypeError("blah"))。 + 在我看来,这是一个错误,我已将其报告为错误。有关更多信息,请访问 http://mail.python.org/pipermail/python-dev/2006-August/068158.html
我要求在内置线程模块中公开此功能,但由于 ctypes 已成为标准库(从 2.5 开始),并且此
功能不太可能与实现无关,因此可能会保持
不公开。
解决方案 22:
假设您想要拥有同一函数的多个线程,在我看来这是通过 id 停止一个线程的最简单的实现:
import time
from threading import Thread
def doit(id=0):
doit.stop=0
print("start id:%d"%id)
while 1:
time.sleep(1)
print(".")
if doit.stop==id:
doit.stop=0
break
print("end thread %d"%id)
t5=Thread(target=doit, args=(5,))
t6=Thread(target=doit, args=(6,))
t5.start() ; t6.start()
time.sleep(2)
doit.stop =5 #kill t5
time.sleep(2)
doit.stop =6 #kill t6
好处是,你可以拥有多个相同和不同的功能,并通过以下方式停止它们:functionname.stop
如果您只想让函数只有一个线程,则无需记住 ID。如果doit.stop
> 0,则停止。
解决方案 23:
正如@Kozyarchuk的回答中提到的,安装跟踪是有效的。由于此答案不包含任何代码,因此这里有一个可用的现成示例:
import sys, threading, time
class TraceThread(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self._run = self.run
self.run = self.settrace_and_run
threading.Thread.start(self)
def settrace_and_run(self):
sys.settrace(self.globaltrace)
self._run()
def globaltrace(self, frame, event, arg):
return self.localtrace if event == 'call' else None
def localtrace(self, frame, event, arg):
if self.killed and event == 'line':
raise SystemExit()
return self.localtrace
def f():
while True:
print('1')
time.sleep(2)
print('2')
time.sleep(2)
print('3')
time.sleep(2)
t = TraceThread(target=f)
t.start()
time.sleep(2.5)
t.killed = True
打印完成后停止1
并且不打印2
。3
解决方案 24:
Python 版本:3.8
使用守护线程来执行我们想要做的事情,如果要终止守护线程,只需要让父线程退出,系统就会终止父线程创建的守护线程。
还支持协程和协程函数。
def main():
start_time = time.perf_counter()
t1 = ExitThread(time.sleep, (10,), debug=False)
t1.start()
time.sleep(0.5)
t1.exit()
try:
print(t1.result_future.result())
except concurrent.futures.CancelledError:
pass
end_time = time.perf_counter()
print(f"time cost {end_time - start_time:0.2f}")
下面是ExitThread源代码
import concurrent.futures
import threading
import typing
import asyncio
class _WorkItem(object):
""" concurrentutures hread.py
"""
def __init__(self, future, fn, args, kwargs, *, debug=None):
self._debug = debug
self.future = future
self.fn = fn
self.args = args
self.kwargs = kwargs
def run(self):
if self._debug:
print("ExitThread._WorkItem run")
if not self.future.set_running_or_notify_cancel():
return
try:
coroutine = None
if asyncio.iscoroutinefunction(self.fn):
coroutine = self.fn(*self.args, **self.kwargs)
elif asyncio.iscoroutine(self.fn):
coroutine = self.fn
if coroutine is None:
result = self.fn(*self.args, **self.kwargs)
else:
result = asyncio.run(coroutine)
if self._debug:
print("_WorkItem done")
except BaseException as exc:
self.future.set_exception(exc)
# Break a reference cycle with the exception 'exc'
self = None
else:
self.future.set_result(result)
class ExitThread:
""" Like a stoppable thread
Using coroutine for target then exit before running may cause RuntimeWarning.
"""
def __init__(self, target: typing.Union[typing.Coroutine, typing.Callable] = None
, args=(), kwargs={}, *, daemon=None, debug=None):
#
self._debug = debug
self._parent_thread = threading.Thread(target=self._parent_thread_run, name="ExitThread_parent_thread"
, daemon=daemon)
self._child_daemon_thread = None
self.result_future = concurrent.futures.Future()
self._workItem = _WorkItem(self.result_future, target, args, kwargs, debug=debug)
self._parent_thread_exit_lock = threading.Lock()
self._parent_thread_exit_lock.acquire()
self._parent_thread_exit_lock_released = False # When done it will be True
self._started = False
self._exited = False
self.result_future.add_done_callback(self._release_parent_thread_exit_lock)
def _parent_thread_run(self):
self._child_daemon_thread = threading.Thread(target=self._child_daemon_thread_run
, name="ExitThread_child_daemon_thread"
, daemon=True)
self._child_daemon_thread.start()
# Block manager thread
self._parent_thread_exit_lock.acquire()
self._parent_thread_exit_lock.release()
if self._debug:
print("ExitThread._parent_thread_run exit")
def _release_parent_thread_exit_lock(self, _future):
if self._debug:
print(f"ExitThread._release_parent_thread_exit_lock {self._parent_thread_exit_lock_released} {_future}")
if not self._parent_thread_exit_lock_released:
self._parent_thread_exit_lock_released = True
self._parent_thread_exit_lock.release()
def _child_daemon_thread_run(self):
self._workItem.run()
def start(self):
if self._debug:
print(f"ExitThread.start {self._started}")
if not self._started:
self._started = True
self._parent_thread.start()
def exit(self):
if self._debug:
print(f"ExitThread.exit exited: {self._exited} lock_released: {self._parent_thread_exit_lock_released}")
if self._parent_thread_exit_lock_released:
return
if not self._exited:
self._exited = True
if not self.result_future.cancel():
if self.result_future.running():
self.result_future.set_exception(concurrent.futures.CancelledError())
解决方案 25:
如果您确实需要终止子任务的能力,请使用替代实现。multiprocessing
并且gevent
两者都支持不加区别地终止“线程”。
Python 的线程不支持取消。千万不要尝试。您的代码很可能会死锁、损坏或泄漏内存,或者产生其他意外的、难以调试的“有趣”效果,这些效果很少发生,而且不确定。
解决方案 26:
ØMQ项目的创始人之一 Pieter Hintjens表示,使用 ØMQ 并避免使用锁、互斥、事件等同步原语是编写多线程程序最明智、最安全的方法:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
这包括告诉子线程应该取消其工作。这可以通过为线程配备 ØMQ 套接字并在该套接字上轮询是否收到指示其应该取消的消息来实现。
该链接还提供了使用 ØMQ 的多线程 Python 代码的示例。
解决方案 27:
这似乎适用于 Windows 7 上的 pywin32
my_thread = threading.Thread()
my_thread.start()
my_thread._Thread__stop()
解决方案 28:
您可以在进程中执行命令,然后使用进程 ID 终止该进程。我需要在两个线程之间进行同步,其中一个线程不会自行返回。
processIds = []
def executeRecord(command):
print(command)
process = subprocess.Popen(command, stdout=subprocess.PIPE)
processIds.append(process.pid)
print(processIds[0])
#Command that doesn't return by itself
process.stdout.read().decode("utf-8")
return;
def recordThread(command, timeOut):
thread = Thread(target=executeRecord, args=(command,))
thread.start()
thread.join(timeOut)
os.kill(processIds.pop(), signal.SIGINT)
return;
解决方案 29:
这是一个糟糕的答案,请参阅评论
具体操作如下:
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()
方法。例如,如果您的线程中有一个套接字,我建议quit()
在您的套接字句柄类中创建一个方法,终止该套接字,然后在thread._Thread__stop()
您的内部运行quit()
。
解决方案 30:
使用setDaemon(True)启动子线程。
def bootstrap(_filename):
mb = ModelBootstrap(filename=_filename) # Has many Daemon threads. All get stopped automatically when main thread is stopped.
t = threading.Thread(target=bootstrap,args=('models.conf',))
t.setDaemon(False)
while True:
t.start()
time.sleep(10) # I am just allowing the sub-thread to run for 10 sec. You can listen on an event to stop execution.
print('Thread stopped')
break
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件