关于python:停止线程:标志与事件

Stop a thread: flag vs. Event

本问题已经有最佳答案,请猛点这里访问。

我看到了一些例子,例如这里使用Event来停止一个线程,我认为布尔标记可以完成这项工作。

事件

1
2
3
4
5
6
7
8
9
10
11
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()

旗帜

1
2
3
4
5
6
7
8
9
10
11
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在多个线程之间共享,我就可以理解这一点,但否则,我就无法理解。

这个邮件列表提示Event更安全,但我不清楚为什么。

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

If I understand the GIL correctly, it synchronizes all access to
Python data structures (such as my boolean 'terminated' flag). If that
is the case, why bother using threading.Event for this purpose?

The GIL is an implementation detail and relying on it to synchronize
things for you isn't futureproof. You're likely to have lots of
warning, but using threading.Event() isn't any harder, and it's more
correct and safer in the long term.

我同意使用Event几乎不会增加开销,所以我可以坚持这一点,但我想了解flag方法的局限性。

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


编程通常不仅仅是让代码在今天工作,而是让它在将来所做的更改中继续工作。

  • 其他的Python实现没有gil。我明天要在Pypy上运行它吗?
  • 实际上,我需要将工作分散到几个流程中。在multiprocessing中交换…它实现了Event(),但如果只使用局部变量,则会失败。
  • 结果是只有在其他几个线程认为应该停止时,代码才应该停止。好吧,用Semaphore()代替Event()…但是很容易用变量错误地实现。

所以,根据字节码如何被中断以及何时可以释放gil,您很可能可以在python中完美地编写多线程程序。但是如果我稍后阅读和更改您的代码,那么如果您使用标准的同步原语,我会更高兴。


我认为您引用的线程中的含义是,设置布尔值不一定是Python中的原子操作。虽然在所有Python对象(gil)上都有一个全局锁,但目前设置属性的所有操作都是原子操作,但这种锁在将来可能不存在。使用Event使操作成为原子操作,因为它使用自己的锁进行访问。

原子的链接是一个Java问题,但与此无关。