Python线程和原子操作


问题内容

我想用同步stop()方法实现线程。

我看过这样的版本:

class Thread1:
    def __init__(self):
        self._stop_event = threading.Event()
        self._thread = None

    def start(self):
        self._thread = threading.Thread(target=self._run)
        self._thread.start()

    def stop(self):
        self._stop_event.set()
        self._thread.join()

    def _run(self):
        while not self._stop_event.is_set():
            self._work()

    def _work(self):
        print("working")

但是我已经读到原子操作是线程安全的,而且在我看来,无需使用它就可以完成Event。所以我想出了这个:

class Thread2:
    def __init__(self):
        self._working = False
        self._thread = None

    def start(self):
        self._working = True
        self._thread = threading.Thread(target=self._run)
        self._thread.start()

    def stop(self):
        self._working = False
        self._thread.join()

    def _run(self):
        while self._working:
            self._work()

    def _work(self):
        print("working")

它认为在C语言中类似的实现将被认为是错误的,因为编译器可以将其放入_working寄存器(甚至进行优化),并且工作线程永远不会知道变量已更改。这样的事情会在Python中发生吗?这个实施正确吗?我并不是要完全避免发生事件或锁定,只是想了解这种原子操作的事情。


问题答案:

据我所知,它在Python中也是不正确的,_working仍然可以通过其他方式进行注册或优化,否则可能会发生其他事情,从而改变其价值。对该字段的读写可以由处理器任意重新排序。

好吧,可以说在多线程世界中,您实际上 不会 问: 为什么这不起作用 ,而是 为什么要保证它起作用

话虽这么说,在大多数情况下,由于GIL保证了:

  • 在任何给定时间仅执行一个解释器命令。
  • 经常强制线程之间进行内存同步。

请记住,GIL是实现细节,如果有人在没有它的情况下重写CPython,它可能会消失。

还应注意,它 应该 在任何实际系统中都以这种方式实现。