python - python 3.7 多线程中的 GIL 行为

标签 python multithreading python-multithreading gil

我正在研究并试图理解 python GIL 和在 python 中使用多线程的最佳实践。我找到了 this presentationthis video

我试图重现演示文稿前 4 张幻灯片中提到的奇怪和疯狂的问题。讲师在视频中也提到了这个问题(前4分钟)。 我写了这个简单的代码来重现这个问题

from threading import Thread
from time import time

BIG_NUMBER = 100000
count = BIG_NUMBER


def countdown(n):
    global count
    for i in range(n):
        count -= 1


start = time()
countdown(count)
end = time()
print('Without Threading: Final count = {final_n}, Execution Time = {exec_time}'.format(final_n=count, exec_time=end - start))

count = BIG_NUMBER
a = Thread(target=countdown, args=(BIG_NUMBER//2,))
b = Thread(target=countdown, args=(BIG_NUMBER//2,))
start = time()
a.start()
b.start()
a.join()
b.join()
end = time()
print('With Threading: Final count = {final_n}, Execution Time = {exec_time}'.format(final_n=count, exec_time=end - start))

但是结果跟论文和视频完全不一样! 使用线程和不使用线程的执行时间几乎相同。有时两种情况中的一种比另一种快一点。

这是我在 Windows 10 下使用多核架构处理器使用 CPython 3.7.3 得到的结果。

Without Threading: Final count = 0, Execution Time = 0.02498459815979004
With Threading: Final count = 21, Execution Time = 0.023985862731933594

另外我根据视频和论文的理解是 GIL 阻止两个线程同时在两个核心中真正并行执行。所以如果这是真的,为什么最终计数变量(在多线程情况下)不是预期的零,并且在每次执行结束时会是一个不同的数字,可能是因为同时操作线程? 在比视频和论文(使用 python 3.2)更新的 python 中,GIL 是否发生了任何变化导致这些不同? 提前致谢

最佳答案

Python 不直接执行。它首先被编译成所谓的 Python bytecode .该字节码在其思想上类似于原始汇编。字节码被执行。

GIL 的作用是不允许两条字节码指令并行运行。尽管一些操作(例如 io)确实在内部发布了 GIL,以在可以证明它不会破坏任何东西时允许真正的并发。

现在您只需要知道count -= 1不会编译成单个字节码指令。它实际上编译成4条指令

LOAD_GLOBAL              1 (count)
LOAD_CONST               1 (1)
INPLACE_SUBTRACT
STORE_GLOBAL             1 (count)

大概意思是

load global variable into local variable
load 1 into local variable
subtract 1 from local variable
set global to the current local variable

这些指令中的每一个都是原子的。但是顺序可能会被线程混合,这就是为什么你看到的是你所看到的。

那么 GIL 的作用是使执行流程串行化。意味着指令一个接一个地发生,没有什么是平行的。因此,当您在理论上运行多个线程时,它们将执行与单线程相同的操作减去在(所谓的)上下文切换上花费的一些时间。我在 Python3.6 中的测试确认执行时间相似。

但是在 Python2.7 中,我的测试显示线程的性能显着下降,大约 1.5 倍。我不知道这是为什么。 GIL 之外的其他事情必须在后台发生。

关于python - python 3.7 多线程中的 GIL 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55496551/

相关文章:

python - 保持 PyQt UI 对线程的响应

python - 使用正则表达式删除标点符号

python - Pandas :多次使用替换方法修改特定级别的Multiindex

python - 在 Mac 上使用 Python 获取文件创建时间

java - 我可以使用什么 API 来等待任务完成

python 日志记录性能比较和选项

python - 由于某些事件,例如,控制台程序是否有任何方法可以改变它们的执行方式按键或代码中的某些事件?

python - 前几行值的总和

c# - 如何在多线程 Windows 服务中使用 Ninject 在每个滴答时获取依赖项(DbContext)的新实例?

java - 运行多个线程(每个线程都有自己的应用程序上下文)并正常关闭