【发布时间】:2018-05-29 18:59:33
【问题描述】:
我可以想到两种方法来打破 Python 线程中的循环,下面是最小的示例:
1 - 使用标记值
from threading import Thread, Event
from time import sleep
class SimpleClass():
def do_something(self):
while self.sentinel:
sleep(1)
print('loop completed')
def start_thread(self):
self.sentinel = True
self.th = Thread(target=self.do_something)
self.th.start()
def stop_thread(self):
self.sentinel = False
self.th.join()
simpleinstance = SimpleClass()
simpleinstance.start_thread()
sleep(5)
simpleinstance.stop_thread()
2 - 使用事件
from threading import Thread, Event
from time import sleep
class SimpleThread(Thread):
def __init__(self):
super(SimpleThread, self).__init__()
self.stoprequest = Event()
def run(self):
while not self.stoprequest.isSet():
sleep(1)
print('loop completed')
def join(self, timeout=None):
self.stoprequest.set()
super(SimpleThread, self).join(timeout)
simpleinstance = SimpleThread()
simpleinstance.start()
sleep(5)
simpleinstance.join()
在 Python 文档中,它讨论了事件,但没有讨论更简单的“哨兵价值”方法(我在 Stack Overflow 上的许多线程答案中都看到了这种方法)。
使用哨兵值有什么缺点吗?
具体来说,它是否会导致错误(我从来没有遇到过错误,但我想如果你试图在 while 循环读取它的同一时刻更改哨兵的值,那么某些东西可能会中断(或者可能是 CPython在这种情况下,GIL 会救我)。什么被认为是最好(最安全)的做法?
【问题讨论】:
-
从我的记忆中,
Event类只是一个标记值加上一个Lock以使其线程安全。看源码。 -
我查看了源代码,这似乎是发生了什么(尽管其中一些超出了我的想象。)但我的问题仍然适用,是一个更简单的哨兵值不是线程安全的或假设使用带有 GIL 的 Python 实现可以吗
-
如果您在线程中使用 select.select() 进行 I/O,则应检查 [docs.python.org/3/library/…。如果你想传递一些基本的控制命令(除了退出),套接字也很好。
-
@Hinni - 有趣的是我不知道你能做到!
-
抱歉,我搞砸了 URL 格式。它是 socket.socketpair()。我经常将它与队列或双端队列一起使用。因此,套接字只是通过写入单个字符将线程从选择中取出,然后读取队列。
标签: python multithreading python-3.x thread-safety python-multithreading