为什么 python threading.Thread 对象有“开始”,但没有“停止”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14482230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does the python threading.Thread object has 'start', but not 'stop'?
提问by Alex
The python module threadinghas an object Threadto be used to run processes and functions in a different thread. This object has a startmethod, but no stopmethod. What is the reason a Threadcannot be stopped my calling a simple stopmethod? I can imagine cases when it is unconvenient to use the joinmethod...
python 模块threading有一个对象Thread用于在不同的线程中运行进程和函数。这个对象有一个start方法,但没有stop方法。Thread无法阻止我调用简单stop方法的原因是什么?我可以想象使用该join方法不方便的情况......
采纳答案by Silas Ray
startcan be generic and make sense because it just fires off the target of the thread, but what would a generic stopdo? Depending upon what your thread is doing, you could have to close network connections, release system resources, dump file and other streams, or any number of other custom, non-trivial tasks. Any system that could do even most of these things in a generic way would add so much overhead to each thread that it wouldn't be worth it, and would be so complicated and shot through with special cases that it would be almost impossible to work with. You can keep track of all created threads without joining them in your main thread, then check their run state and pass them some sort of termination message when the main thread shuts itself down though.
start可以是泛型并且有意义,因为它只是触发线程的目标,但是泛型会stop做什么?根据您的线程正在执行的操作,您可能必须关闭网络连接、释放系统资源、转储文件和其他流,或任何数量的其他自定义、非平凡任务。任何可以以通用方式完成大部分这些事情的系统都会为每个线程增加如此多的开销,以至于不值得,并且会非常复杂并且会遇到特殊情况,几乎不可能工作和。您可以跟踪所有创建的线程,而无需join在主线程中执行它们,然后检查它们的运行状态并在主线程自行关闭时向它们传递某种终止消息。
回答by Some programmer dude
On some platforms you can't forcibly "stop" a thread. It's also bad to do it since then the thread won't be able to clean up allocated resources. And it might happen when the thread is doing something important, like I/O.
在某些平台上,您不能强行“停止”线程。这样做也不好,因为这样线程将无法清理分配的资源。当线程正在做一些重要的事情时可能会发生,比如 I/O。
回答by Has QUIT--Anony-Mousse
Killing threads in a reliable fashion is not very easy. Think of the cleanups required: which locks (that might be shared with other threads!) should automatically be released? Otherwise, you will easily run into a deadlock!
以可靠的方式杀死线程并不容易。想想所需的清理工作:哪些锁(可能与其他线程共享!)应该自动释放?否则很容易陷入僵局!
The better way is to implement a proper shutdown yourself, and then set
更好的方法是自己实现适当的关闭,然后设置
mythread.shutdown = True
mythread.join()
to stop the thread.
停止线程。
Of course your thread should do something like
当然你的线程应该做类似的事情
while not this.shutdown:
continueDoingSomething()
releaseThreadSpecificLocksAndResources()
to frequently check for the shutdown flag. Alternatively, you can rely on OS-specific signaling mechanisms to interrupta thread, catch the interrupt, and then cleanup.
经常检查关闭标志。或者,您可以依靠特定于操作系统的信号机制来中断线程、捕获中断,然后进行清理。
The cleanupis the most important part!
该清理是最重要的部分!
回答by Kansha
Stopping a thread should be up to the programmer to implement. Such as designing your thread to check it there are any requests for it to terminate immediately. If python (or any threading language) allowed you to just stop a thread then you would have code that just stopped. This is bug prone, etc.
停止线程应该由程序员来实现。比如设计你的线程来检查它是否有任何要求它立即终止的请求。如果python(或任何线程语言)允许您停止一个线程,那么您将拥有刚刚停止的代码。这很容易出错,等等。
Imagine if your thread as writing output to a file when you killed/stopped it. Then the file might be unfinished and corrupt. However if you simple signaled the thread you wanted it to stop then it could close the file, delete it, etc. You, the programmer, decided how to handle it. Python can't guess for you.
想象一下,如果您的线程在您杀死/停止它时将输出写入文件。那么该文件可能未完成且已损坏。但是,如果您简单地向线程发出信号,您希望它停止,那么它可以关闭文件、删除它等。您,程序员,决定如何处理它。Python 无法为您猜测。
I'd suggest reading up on multi-threading theory. A decent start: http://en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
我建议阅读多线程理论。一个不错的开始:http: //en.wikipedia.org/wiki/Multithreading_(software)#Multithreading
回答by Noctis Skytower
It is definitely possible to implement a Thread.stopmethod as shown in the following example code:
绝对可以实现Thread.stop如下示例代码所示的方法:
import threading
import sys
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()
################################################################################
import time
def main():
test = Thread2(target=printer)
test.start()
time.sleep(1)
test.stop()
test.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
if __name__ == '__main__':
main()
The Thread3class appears to run code approximately 33% faster than the Thread2class.
的Thread3类似乎比快大约33%的运行代码Thread2类。
Addendum:
附录:
With sufficient knowledge of Python's C API and the use of the ctypesmodule, it is possible to write a far more efficient way of stopping a thread when desired. The problem with using sys.settraceis 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:
通过对 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)

