Python的全局锁GIL解析

在这里插入图片描述

Python的全局锁(GIL)是 CPython 解释器实现中的一个机制,用来确保任何时候只有一个线程执行 Python 字节码。这一机制存在于 CPython 中,主要是为了确保线程操作中的数据一致性,但也因此限制了多线程的并行执行效率。尤其是在多核 CPU 上,GIL 使得 CPU 的多核优势难以在纯 Python 的多线程程序中得到完全利用。

GIL 的基本知识

  • 作用:GIL 保证在 CPython 中,同时只能有一个线程执行 Python 代码(即字节码)。
  • 原因:CPython 的许多内建对象(如字典、列表等)不是线程安全的。通过使用 GIL,CPython 避免了在这些对象上加锁,从而简化了对象的内存管理。
  • 影响:GIL 会使得多线程程序在多核 CPU 上无法完全并行,导致在 CPU 密集型任务中表现不佳。但是对于 I/O 密集型的任务(如网络 I/O、文件读写等),GIL 的影响相对较小。

CPython 实现 GIL 的基本原理

在 CPython 中,GIL 被实现为一个互斥锁。每次只有持有 GIL 的线程才能执行 Python 字节码,其它线程则处于等待状态。GIL 的执行流程如下:

  1. 一个线程持有 GIL 时,可以执行 Python 代码。
  2. 执行一段时间后,线程会释放 GIL,让其他线程有机会获得它(在 CPython 中通常会计数 Python 的指令)。
  3. 另一个线程获得 GIL 并开始执行。
简化 C++ 示例:模拟 GIL 的作用

以下代码模拟了 GIL 在多线程中的作用。它展示了如何使用一个全局互斥锁来控制线程执行的访问权限。

#include <iostream>
#include <thread>
#include <mutex>std::mutex gil; // 模拟 GILvoid python_thread(int thread_id) {for (int i = 0; i < 5; ++i) {std::lock_guard<std::mutex> lock(gil); // 获得“GIL”std::cout << "线程 " << thread_id << " 正在执行 Python 代码, i = " << i << std::endl;} // 离开作用域时自动释放“GIL”
}int main() {std::thread t1(python_thread, 1);std::thread t2(python_thread, 2);t1.join();t2.join();return 0;
}

在这个示例中,我们模拟了 GIL 的作用,通过 std::mutex 来控制每个线程对共享资源的访问。这段代码展示了线程如何在每次需要执行 Python 代码时获取 GIL,其他线程必须等待直到 GIL 被释放。

Python 中多线程的简单示例

以下 Python 代码展示了 GIL 对多线程程序的影响。在这个例子中,我们使用了 CPU 密集型的计算,观察到 GIL 的存在会导致多线程表现不如预期。

import threading
import timedef cpu_bound_task():x = 0for _ in range(100000000):x += 1print("完成计算")# 启动两个线程执行 CPU 密集型任务
start_time = time.time()
t1 = threading.Thread(target=cpu_bound_task)
t2 = threading.Thread(target=cpu_bound_task)
t1.start()
t2.start()
t1.join()
t2.join()
end_time = time.time()print(f"总耗时: {end_time - start_time} 秒")

在这个 Python 代码中,两个线程分别执行同样的 CPU 密集型任务,但因为 GIL 的存在,它们并不能并行运行。执行时间通常会接近单线程的 2 倍,而不是预期中的加速。

总结

  • GIL 是什么:GIL 是一个全局锁,确保同一时间只有一个线程执行 Python 字节码。
  • GIL 的原因:主要为了保证数据一致性,避免加锁带来的复杂性。
  • GIL 的影响:GIL 限制了多核 CPU 上的 Python 多线程性能表现,尤其是在 CPU 密集型任务中;但对于 I/O 密集型任务,影响较小。

通过示例代码,我们可以看到 GIL 如何限制了多线程 Python 程序的并行性。在实际应用中,Python 程序员可以通过使用多进程(而不是多线程)来避开 GIL 的影响,或者使用如 CythonNumpy 等基于 C 实现的库来提高性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/462073.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于vue框架的的考研信息共享平台v0eyp(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;国家政策,用户,院校政策,院校信息,考研资料,资料分类,考研论坛 开题报告内容 基于Vue框架的考研信息共享平台开题报告 一、研究背景与意义 随着考研人数的逐年增长&#xff0c;考研学生对高效、便捷、个性化的信息获取需求愈发强烈。…

抽丝剥茧 分布式服务框架设计 理论设计篇

1、概述 前面几篇文章给大家详细的介绍了Zookeeper的基础概念以及应用的领域&#xff0c;今天我们讨论的话题是如何自研一套分布式服务框架。早些年有很多基于Dubbo和Zookeeper的分布式系统&#xff0c;这篇文章我们就来聊下如何设计一个分布式服务框架。 2、系统间交互 2.1、…

C++STL——list

C教学总目录 list 1、list简介2、构造函数3、迭代器4、访问和容量函数5、修改类函数6、操作类函数 1、list简介 list是带头双向循环链表&#xff0c;也是模板类&#xff0c;使用时要指明类型&#xff0c;包含于头文件<list> 由于list是双向循环链表&#xff0c;在任意位置…

YoloV8改进策略:Block改进|RFE模块,提高小物体的识别精度|即插即用|代码+修改过程

摘要 论文介绍 本文介绍了一种基于YOLOv5的人脸检测方法,命名为YOLO-FaceV2。该方法旨在解决人脸检测中的尺度变化、简单与困难样本不平衡以及人脸遮挡等问题。通过引入一系列创新模块和损失函数,YOLO-FaceV2在WiderFace数据集上取得了优异的表现,特别是在小物体、遮挡和困…

leaflet矢量瓦片vetorgrid显示聚合和图标裁剪显示不全的问题

1、问题现象 使用leaflet显示矢量瓦片会出现图片挤压的问题和图片裁剪显示不全的问题 2、解决办法和思路 1&#xff09;数据抽稀 方法一&#xff1a;在createTile方法通过控制feature在单张瓦片里面显示的数量&#xff0c;在小层级的时候进行筛选过滤&#xff0c;对点数据类…

Gitee push 文件

1、背景 想将自己的plecs仿真放到git中管理&#xff0c;以防丢失&#xff0c;以防乱改之后丢失之前版本仿真。此操作说明默认用户已下载git。 2、操作步骤 2.1 开启Git Bash 在文件夹中右键&#xff0c;开启Git Bash。 2.2 克隆文件 在Git Bash中打git clone git地址&#…

gitee 使用 webhoot 触发 Jenkins 自动构建

一、插件下载和配置 Manage Jenkins>Plugin Manager 搜索 gitee 进行安装 插件配置 1、前往Jenkins -> Manage Jenkins -> System -> Gitee Configuration -> Gitee connections 2、在 Connection name 中输入 Gitee 或者你想要的名字 3、Gitee host URL 中…

【JavaEE初阶 — 多线程】Thread类的属性

目录 Thread类的属性 1.Thread 的常见构造方法 2.Thread 的几个常见属性 2.1 前台线程与后台线程 2.2 setDaemon() 2.3 isAlive() Thread类的属性 Thread 类是JVM 用来管理线程的一个类&#xff0c;换句话说&#xff0c;每个线程都有一个唯一的Thread 对象与之关联&…

yocto是如何收集recipes,如何加入现有的bb文件

yocto通常是如何收集recipes: 在Yocto中&#xff0c;通过以下方式收集recipes&#xff1a; 层&#xff08;Layers&#xff09; Yocto项目使用层来组织recipes。层是包含配置文件、recipes和其他相关文件的目录结构。每个层有自己的目录&#xff0c;其中 recipes-* 目录用于存…

原生鸿蒙的竞争力到底如何?

目录 1. 崛起与挑战2. 安全机制3. 自动化检测前移4. 深入探讨开发者服务优势 1. 崛起与挑战 长期以来&#xff0c;移动操作系统市场被IOS和安卓所垄断&#xff0c;一直都难以推出完整的自主系统&#xff0c;面临诸多挑战&#xff0c;如推广困难、应用适配难度大&#xff0c;以及…

sublime Text中设置编码为GBK

要在sublime Text中设置编码为GBK&#xff0c;请按照以下步骤操作 1.打开Sublime Text编辑器, 2.点击菜单栏中的“Preferences”(首选项)选项&#xff0c;找打Package Control选项。 3.点击Package Control&#xff0c;随后搜索Install Package并点击&#xff0c;如下图 4.再…

KPRCB结构之ReadySummary和DispatcherReadyListHead

ReadySummary: Uint4B DispatcherReadyListHead : [32] _LIST_ENTRY 请参考 _KTHREAD *__fastcall KiSelectReadyThread(ULONG LowPriority, _KPRCB *Prcb)

Python爬虫:揭开淘宝商品描述的神秘面纱

在这个信息爆炸的时代&#xff0c;我们每天都在和时间赛跑。作为一名Python开发者&#xff0c;你是否曾梦想拥有超能力&#xff0c;能够瞬间揭开淘宝商品描述的神秘面纱&#xff1f;今天&#xff0c;就让我们一起化身为代码界的“福尔摩斯”&#xff0c;使用Python爬虫技术&…

HTML 多媒体标签详解:<img>、<object> 与 <embed>

文章目录 1. `<img>` 标签主要属性示例注意事项2. `<object>` 标签概述主要属性示例注意事项3. `<embed>` 标签概述主要属性示例注意事项小结在现代网页设计中,多媒体内容的使用变得越来越重要,因为它能够有效增强用户体验、吸引注意力并传达信息。HTML 提…

台式电脑如何改ip地址:全面解析与实操指南

有时候&#xff0c;由于IP地址冲突、网络安全、隐私保护或特定应用需求&#xff0c;我们可能需要更改台式电脑的IP地址。然而&#xff0c;对于不熟悉网络设置的用户来说&#xff0c;这一过程可能显得复杂而陌生。本文将通过全面解析与实操指南&#xff0c;帮助大家轻松掌握台式…

跟着红队笔记学习 tmux:渗透测试中的多终端利器

内容预览 ≧∀≦ゞ 跟着红队笔记学习 tmux&#xff1a;渗透测试中的多终端利器进入 tmux 前的准备tmux 概念简介tmux 基础操作会话管理命令会话管理快捷键会话内和会话外命令的区别 tmux 窗口和面板管理新建和管理窗口分割窗口为面板切换面板面板放大与恢复调整面板大小关闭面板…

【机器学习】24. 聚类-层次式 Hierarchical Clustering

1. 优势和缺点 优点&#xff1a; 无需提前指定集群的数量 通过对树状图进行不同层次的切割&#xff0c;可以得到所需数量的簇。树状图提供了一个有用的可视化-集群过程的可解释的描述树状图可能揭示一个有意义的分类 缺点&#xff1a; 计算复杂度较大, 限制了其在大规模数据…

移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (2) - 移植 nanovg

AWTK 使用 nanovg 作为显示的后端&#xff0c;能否将 nanovg 成功移植到 HarmonyOS 上是一个关键问题&#xff0c;所以我们先尝试移植 nanovg&#xff0c;不过实际情况比预想的要简单&#xff0c;整个过程没有遇到任何意外的问题。 1. 将 AWTK 的代码取到 entry/src/main/cpp …

函数调用方法背后的原理

编译器实现函数调用时所遵循的一系列规则称为函数的“调用约定&#xff08;Calling Convention&#xff09;”&#xff0c;x86-64平台上的编译器随着操作系统的不同而有不同的约定。Windows上采用的是Wx64/Vector的标准,而类unix上采用systemV AMD64 ABI的调用标准。统一的调用…

Pinpoint(APM)进阶--插件开发

接上文 pinpoint支持编写插件来扩展监控的覆盖范围 这里重申下pinpoint一个trace的基本构成&#xff08;最小单元为span&#xff09; 插件结构 pinpoint插件由type-provider.yml 和实现组成 type-provider.yml 定义给插件使用的ServiceTypes和AnnotationKeys&#xff0c;并…