【问题标题】:How can asyncio ever not be thread safe considering the GIL?考虑到 GIL,asyncio 怎么可能不是线程安全的?
【发布时间】:2017-01-04 08:42:51
【问题描述】:

asyncio docs 读取:

大多数异步对象都不是线程安全的。只有在访问事件循环之外的对象时才应该担心。

有人可以对此进行解释或举例说明滥用 asyncio 如何导致对线程之间共享的对象的不同步写入吗?我认为 GIL 意味着一次只有一个线程可以运行解释器,因此在解释器中发生的事件(例如读取和写入 Python 对象)在线程之间很容易同步。

上面引用中的第二句话听起来像是一个线索,但我不知道该怎么做。

我猜一个线程总是会通过释放 GIL 并决定写入 Python 对象来造成严重破坏,但这并不是 asyncio 特有的,所以我不认为这就是文档所指的内容。

这可能是因为 asyncio PEP 为某些 asyncio 对象保留了不是线程安全的选项,即使目前 CPython 中的实现恰好是线程安全的?

【问题讨论】:

  • 有些操作需要多条指令同步,其中Python之间可以由不同的线程解释。 GIL 从不简单地同步 Python 程序,与 asyncio 无关。 -- 它只是确保 Python 对象在 C 级别上是线程安全的,而不是在 Python 级别上。

标签: python python-multithreading python-asyncio cpython thread-synchronization


【解决方案1】:

其实不,每个线程就是这样,解释器的一个新线程。

它是由操作系统管理的真正线程,而不是仅用于 Python 虚拟机中的 Python 代码的内部管理线程。

需要 GIL 来防止基于操作系统的线程搞乱 Python 对象。

想象一个线程在一个 CPU 上,另一个在另一个 CPU 上。纯并行线程,用汇编语言编写。两者同时试图更改注册表值。根本不是理想的情况。访问相同内存位置的汇编指令最终会争先恐后地决定何时何地移动什么。最终这样一个动作的结果很容易导致分段错误。好吧,如果我们用 C 语言编写,C 会控制该部分,这样就不会在 C 代码中发生这种情况。 GIL 对 C 级别的 Python 代码执行相同的操作。因此,实现 Python 对象的代码在更改它们时不会失去其原子性。想象一个线程将一个值插入到一个列表中,该列表刚刚在另一个线程中向下移动,因为另一个线程从中删除了一些元素。如果没有 GIL,这会崩溃。

GIL 对线程内代码的原子性没有任何作用。它仅用于内部内存管理。

即使你有像 deque() 这样的线程安全对象,如果你一次对它执行多个操作,而无需额外的锁,你也可以从插入在其间某处的另一个线程获得结果。哎呀,问题出现了!

假设一个线程从堆栈中取出一个对象,检查它的某些内容,如果条件正确,则将其删除。

stack = [2,3,4,5,6,7,8]
def thread1 ():
    while 1:
        v = stack[0]
        sleep(0.001)
        if v%2==0: del stack[0]
        sleep(0.001)

当然,这是愚蠢的,应该使用 stack.pop(0) 来避免这种情况。但这是一个例子。

让另一个线程每 0.002 秒添加到堆栈中:

def thread2 ():
    while 1:
        stack.insert(0, stack[-1]+1)
        sleep(0.002)

现在如果你这样做:

thread(thread2,())
sleep(1)
thread(thread1,())

会有一个时刻,虽然不太可能,thread2() 会尝试在 thread1() 的检索和删除之间准确地堆叠新项目。因此,thread1() 将删除一个新添加的项目,而不是正在检查的项目。结果不符合我们的意愿。因此,GIL 不控制我们在线程中执行的操作,而只是在更基本的意义上线程对彼此执行的操作。

假设您编写了一个服务器来购买某些活动的门票。两个用户连接并尝试同时购买同一张票。如果您不小心,用户可能会最终一个坐在另一个之上。

线程安全对象是执行操作的对象,在第一个操作完成之前,它不允许其他操作发生。

例如,如果您在一个线程中对 deque() 进行迭代,而在它的中间另一个线程尝试追加某些内容,则 append() 将阻塞,直到第一个线程完成对它的迭代。这是线程安全的。

【讨论】:

  • GIL doesn't control what we are doing in our threads, just what threads are doing to each-other - 这条线是纯金的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-16
  • 2016-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
相关资源
最近更新 更多