停止一个主题:标志与事件

时间:2017-05-09 20:20:07

标签: python python-multithreading

我看到使用e.g. here来阻止线程的示例Event,我认为布尔标志可以完成这项工作。

事件

class MyThread(threading.Thread):

    def __init__(self):
        self._please_stop = threading.Event()

    def run(self):
        while not self._please_stop.is_set():
        [...]

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

标志

class MyThread(threading.Thread):

    def __init__(self):
        self._please_stop = False

    def run(self):
        while not self._please_stop:
        [...]

    def stop(self):
        self._please_stop = True

在这里使用Event有什么好处?不使用其wait方法。是什么让它比布尔标志更好?

如果在多个线程之间共享相同的Event,我可以看到这一点,否则,我无法得到它。

This mailing list thread表示Event会更安全,但我不明白为什么。

更确切地说,我不理解这两段:

  

如果我正确理解了GIL,它会同步所有访问权限   Python数据结构(例如我的布尔'终止'标志)。如果说   是这样的,为什么要为此目的使用threading.Event呢?

     

GIL是一个实现细节,依赖于它来进行同步   适合你的事情不是未来的。你很可能会有很多   警告,但使用threading.Event()并不是更难,而且更多   从长远来看,这是正确和安全的。

我同意使用Event增加接近没有开销,所以我可以坚持这一点,但我想了解标志方法的局限性。

(我正在使用Python3,所以我不关心Python2的限制,如果有的话,尽管这些在这里完全值得一提。)

2 个答案:

答案 0 :(得分:2)

编程通常不仅仅是让代码在今天运行,而是让它继续通过将来会发生的变化。

  • 其他Python实现没有GIL。我想明天在pypy运行吗?
  • 实际上,我需要将工作分散到多个流程中。交换multiprocessing ...实现Event()但如果您只使用本地变量则会失败。
  • 事实证明,只有当其他几个线程认为它应该停止时,代码应该停止。好吧,使用Semaphore()而不是Event() ...但很容易用变量错误地实现。

所以,很可能你可以在Python中完全正确地编写多线程程序,依赖于字节码如何被中断以及何时可以释放GIL ......但如果我以后正在阅读并更改你的代码,我会更开心如果您使用标准同步原语。

答案 1 :(得分:1)

我认为你引用的主题的含义是设置一个布尔值不一定是Python中的atomic操作。虽然对所有Python对象(GIL)进行全局锁定会使所有设置属性的操作暂时显示为原子,但此类锁定将来可能不存在。使用Event使操作成为原子操作,因为它使用自己的锁进行访问。

原子的链接是一个Java问题,但由于这个原因,它并没有那么重要。