python 3.7 多线程中的 GIL 行为

2024-03-19

我正在研究并尝试了解 python GIL 以及在 python 中使用多线程的最佳实践。我发现这个演示文稿 https://www.dabeaz.com/python/UnderstandingGIL.pdf and 这个视频 https://www.youtube.com/watch?v=Obt-vMVdM8s

我试图重现演示文稿前 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字节码 https://docs.python.org/3/library/dis.html。该字节码的思想与原始汇编类似。字节码被执行。

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

现在你所需要知道的是count -= 1 does not编译成单个字节码指令。它实际上编译成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

这些指令中的每一个is原子。但是顺序可以通过线程混合,这就是为什么你看到的就是你所看到的。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python 3.7 多线程中的 GIL 行为 的相关文章

  • 将 yerr/xerr 绘制为阴影区域而不是误差线

    在 matplotlib 中 如何将误差绘制为阴影区域而不是误差条 例如 而不是 忽略示例图中各点之间的平滑插值 这需要进行一些手动插值 或者只是获得更高分辨率的数据 您可以使用pyplot fill between https matpl
  • 如何为未捕获的异常处理程序编写单元测试

    我有一个函数可以捕获uncaught例外情况 如下 有没有办法编写一个单元测试来执行uncaught exception handler 功能正常 但测试正常退出 import logging def config logger logge
  • 如何调整 matplotlib 单选按钮的大小和纵横比?

    我已经尝试了几个小时来使简单的单选按钮列表的大小和纵横比正确 但没有成功 首先 导入模块 import matplotlib pyplot as plt from matplotlib widgets import RadioButtons
  • 使用 Python 3 动态插入到 sqlite

    我想使用 sqlite 写入多个表 但我不想提前手动指定查询 有数十种可能的排列 例如 def insert sqlite tablename data list global dbc dbc execute insert into tab
  • 使用 Pytest 的参数化添加测试功能的描述

    当其中一个测试失败时 可以在测试正在测试的内容的参数化中添加描述 快速了解测试失败的原因 有时您不知道测试失败的原因 您必须查看代码 通过每个测试的描述 您就可以知道 例如 pytest mark parametrize num1 num2
  • numpy:高效执行数组的复杂重塑

    我正在将供应商提供的大型二进制数组读入 2D numpy 数组 tempfid M N load data data numpy fromfile file dirname fid dtype numpy dtype i4 convert
  • 将 pandas 剪切操作转换为常规字符串

    我明白了 pandas cut 操作的输出 0 0 20 1 0 20 2 0 20 3 0 20 4 0 20 5 0 20 6 0 20 7 0 20 8 0 20 9 0 20 如何将 0 20 转换为 0 20 我正在这样做 str
  • 是否有一个包可以维护所有带有符号的货币列表?

    是否有一个 python 包提供所有 或相当完整 货币的列表与符号 如美元的 有优秀的pycountry 贪财的 https github com limist py moneyed and ccy http code google com
  • 在 Mac OS X 上安装 libxml2 时出现问题

    我正在尝试在我的 Mac 操作系统 10 6 4 上安装 libxml2 我实际上正在尝试在 Python 中运行 Scrapy 脚本 这需要我安装 Twisted Zope 现在还需要安装 libxml2 我已经下载了最新版本 2 7 7
  • App Engine 实体到字典

    将 google app engine 实体 在 python 中 复制到字典对象的好方法是什么 我正在使用 db Expando 对象 所有属性均为扩展属性 Thanks 有一个名为foo尝试 foo dict
  • Flask 应用程序路由中的多个参数

    烧瓶怎么写app route如果我在 URL 调用中有多个参数 这是我从 AJax 调用的 URL http 0 0 0 0 8888 createcm summary VVV change Feauure 我试图写我的烧瓶app rout
  • 如何在 Seaborn 中的热图轴上表达类

    我使用 Seaborn 创建了一个非常简单的热图 显示相似性方阵 这是我使用的一行代码 sns heatmap sim mat linewidths 0 square True robust True sns plt show 这是我得到的
  • 使用 suds SOAP 库进行 HTTP 身份验证的奇怪行为

    我有一个正在运行的 python 程序 它使用 suds 通过 SOAP 获取大量数据 Web服务是通过分页功能实现的 这样我就可以抓取nnn每个 fetch 调用的行并获取下一个nnn与后续的电话 如果我使用如下代码向 HTTP 服务器进
  • 基于值而不是类型的单次调度

    我在 Django 上构建 SPA 并且有一个庞大的功能 其中包含许多功能if用于检查我的对象字段的状态名称的语句 像这样 if self state new do some logic if self state archive do s
  • 仅允许正小数

    在我的 Django 模型中 我创建了一个如下所示的小数字段 price models DecimalField u Price decimal places 2 max digits 12 显然 价格为负或零是没有意义的 有没有办法将小数
  • 在 numpy 中连接维度

    我有x 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 2 3 I want 1 2 3 4 5 6 7 8 9 10 11 12 shape 2 6 也就是说 我想连接中间维度的所有项目 在这种特殊情况下我可以得到这
  • 在matlab中,如何读取python pickle文件?

    在 python 中 我生成了一个 p 数据文件 pickle dump allData open myallData p wb 现在我想在Matlab中读取myallData p 我的Matlab安装在Windows 8下 其中没有Pyt
  • 如何绘制更大的边界框和仅裁剪边界框文本 Python Opencv

    我正在使用 easyocr 来检测图像中的文本 该方法给出输出边界框 输入图像如下所示 Image 1 Image 2 使用下面的代码获得输出图像 But I want to draw a Single Bigger bounding bo
  • 如何使用xlwt设置文本颜色

    我无法找到有关如何设置文本颜色的文档 在 xlwt 中如何完成以下操作 style xlwt XFStyle bold font xlwt Font font bold True style font font background col
  • 描述符“join”需要“unicode”对象,但收到“str”

    代码改编自here http wiki geany org howtos convert camelcase from foo bar to Foo Bar def lower case underscore to camel case s

随机推荐