python hack_Python进阶:深入GIL(上篇)

Python进阶:深入GIL(上篇)HackPython致力于有趣有价值的编程教学

简介

熟悉Python的人理应都听过GIL(Global Interpreter Lock,全局解释器锁) ,大概也知道它就是造成Python多线程并发其实是「伪并行」的核心原因,但依旧很多人没有深入其中,所以HackPython尝试以上、下两篇文章来阐释GIL,分别从其表现现象、对应源码以及Python对GIL改进等方面进行讨论 。

线程与进程

在讨论GIL前,先通过简单的文字描述一下线程与进程并理解其中的关系。

当我们启动一个程序时,系统中就至少启动了一个对应的进程,即一个程序至少对应一个进程 。所谓程序,它其实是一种静态的资源实体,就是一堆代码,存在于硬盘中,本身没有任何运行的含义,而进程是动态的,它是程序操作某个数据集时的动态实体,存在于内存中 。

一个进程可以包含多个线程,这些线程可以共享当前进程中的内存空间 ,这种特性就出现了线程不安全的概念,即多个线程同时使用了一个空间,导致程序逻辑错误 ,常见的方式就是使用锁或信号量等机制来限制公共资源的使用 。

Python多线程的伪并行

Python中可以使用「threading」模块来创建并使用多线程,为了直观比较,先试一下一个没有使用多线程的代码 ,如下:import time

def add(n):

sum = 0

while sum <= n:

sum += 1

print(f'sum:{sum}')

if __name__ == '__main__':

start = time.time()

add(500000000)

print('run time: %s'%str(time.time() - start))

代码非常简单,就是一个add()方法一直做累加操作,运行结果为 :python 5.py

sum:500000001

run time: 23.80576515197754

那我使用多线程效果会不会好一些呢?凭感觉直观而言,应该是会的 ,因为上面的程序只使用了一个线程,那我开两个线程,让其同时工作,其运行时间应该短一半才对 ,但事实时使用多线程后,运行时间依旧没有变动 ,多线程版本的代码如下:import threading, time

def add(n):

sum = 0

while sum <= n:

sum += 1

print(f'sum:{sum}')

if __name__ == '__main__':

start = time.time()

n = 500000000

t1 = threading.Thread(target=add, args=[n//2])

t2 = threading.Thread(target=add, args=[n//2])

t1.start()

t2.start()

t1.join()

t2.join()

print('run time: %s'%str(time.time() - start))

为了让相加的数量相近,这里每个线程只需要执行「n//2」次,使用join的目的是得等线程运行完后,再执行后续的逻辑,这里只是为了方便记录运行时间 。运行结果如下:python 6.py

sum:250000001

sum:250000001

run time: 23.04693603515625

发现跟一开始单线程的程序在运行时间上没有什么差异,而造成这种现象的原因就是GIL ,需要注意的是,GIL只存在于通过C语言实现的Python解释器上,即CPython上 ,后人为了绕过GIL的问题利用Java开发了Jpython或使用Python自己开发了自己的解释器PyPy,这些上都不存在GIL全局解释器锁的问题 ,但CPython才是当前最多人使用的主流Python解释器 。

在CPython中,每一个Python线程执行前都需要去获得GIL锁 ,获得该锁的线程才可以执行,没有获得的只能等待 ,当具有GIL锁的线程运行完成后,其他等待的线程就会去争夺GIL锁,这就造成了,在Python中使用多线程,但同一时刻下依旧只有一个线程在运行 ,所以Python多线程其实并不是「并行」的,而是「并发」 。

看到下图,图中是Python中GIL的工作实例,其中有3个线程,线程与线程之间是顺序执行的 ,每个线程开始执行时都会去获得GIL,防止其他线程线程运行 ,每执行完一段时间后,就会释放GIL,让别的线程可以去争夺执行权限,如果自己本身也没有执行完,则本身也会参与这次争夺 。

可以发现,Python中的线程工作一段时间后,会主动释放GIL,这是为了让其他线程都有机会执行 ,而释放的时机就涉及到了「检查间隔」(check interval)机制 ,在早期版本的Python中,检查机制是100ticks,而Python3后,每15毫米使用一次检查间隔,然后就会释放GIL锁 。

但需要注意的是线程有了GIL后并不意味着使用Python多线程时不需要考虑线程安全 ,「GIL的存在是为了方便使用C语言编写CPython解释器的编写者,而顶层使用Python时依旧要考虑线程安全」 ,在下一篇中会从原始编码层面来解释存在GIL后,依旧会有线程不安全现象的原因。

多进程实现并行

GIL的存在让Python多线程在运行CPU密集型性程序时显得非常无力,为了绕过GIL的限制,一种简单的方法就是使用多进程 ,这是因为GIL只会存在于线程级别,即一个进程为了确保某一时刻下只有一个线程在运行,才使用GIL ,但多个进程之间并不会出现这种限制,不同的进程会运行在CPU不同的核上,实现真正的「并行」 。

通过进程的方式将上面的任务再执行一遍,看一下运行时长,具体代码如下:from multiprocessing import Process

import time

def add(procname, n):

sum = 0

while sum <= n:

sum += 1

print(f'process name: {procname}')

print(f'sum: {sum}')

if __name__ == '__main__':

start = time.time()

n = 500000000

p1 = Process(target=add, args=('Proc-1',n//2))

p2 = Process(target=add, args=('Proc-2',n//2))

p1.start()

p2.start()

p1.join()

p2.join()

print('run time: %s'%str(time.time() - start))

Python中多进程可以使用 multiprocessing 这个库,使用方法与使用线程类似 ,代码中启用了两个进程,分别运行 n//2 数据量的数据,其结果如下:python 7.py

process name: Proc-1

sum: 250000001

process name: Proc-2

sum: 250000001

run time: 12.768253087997437

从结果可以看出,时间确实减少了一半左右,多进程状态下确实是真正的「并行」。

如何绕过GIL?

有了多进程后,大部分程序都可以通过多进程的方式绕过GIL ,但如果依旧不满足,就需要使用C/C++来实现这部分代码,并生成对应的so或dll文件,再通过Python的ctypes将其调用起来 ,Python中很多对计算性能有较高要求的库都采用了这种方式,如Numpy、Pandas等等 。

如果你对程序的性能要求的特别严格,此时更好的方法是选择其他语言 。

结尾

本节简单的讨论了Python中GIL相关的内容,在下一篇中会从代码层面再次深入的讨论GIL的相关内容,欢迎学习 HackPython 的教学课程并感觉您的阅读与支持。

参考文章:

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

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

相关文章

ifconfig相关

目录 一、ifconfig command not found 二、ifconfig结果相关参数解释 一、ifconfig command not found 出现这个问题的原因是新版本的linux默认不带 ifconfig&#xff08;我这里是centos7&#xff0c;最小安装&#xff09;&#xff0c;官方推荐使用ip命令查看ip&#xff1a;i…

k8s jenkins pipeline 多分支发布_给 Jenkins 换一个新皮肤:BlueOcean

BlueOcean是什么Jenkins是一款Java开发的跨平台持续集成和持续发布的开源项目&#xff0c;它具有如下特征&#xff1a;安装及迁移方便&#xff1a;安装直接部署war包&#xff0c;迁移只需替换JENKINS_HOME目录。配置方便&#xff1a;可视化后台操作。丰富的插件生态圈&#xff…

python能做什么效果_python对于做SEO主要有什么作用?

一直没完整的解释这个问题&#xff0c;这边详细说下吧。准确说不是Python对SEO有什么作用&#xff0c;而是会一门程序语言对SEO有什么用。Python仅是诸多程序语言中&#xff0c;个人评估下来最为推荐的一种&#xff0c;但用其它程序语言一般也没太大的差别。后面简单起见都以Py…

linux文件目录解释

/根目录/bin存放用户使用的命令&#xff0c;二进制的可执行文件/boot开机启动相关的文件/dev系统中必要的设备文件/etc系统配置文件/home普通用户家目录&#xff0c;在目录下有与普通用户同名的目录rootroot用户的家目录/lib,/lib64库文件/media可以热插拔的设备的挂载点/mnt临…

xpath 取标签下所有文字内容_xpath提取目录下所有标签内的内容,递归 //text()...

利用xpath来提取所有标签里面的内容,即使标签头不同 #-*-coding:utf8-*- import re import os from lxml import etree html = 测试-常规用法 我是谁 who am i!你是谁!who you are! selector = etree.HTML(html) for k in range(1,3): chinese = selector.xpath(//div[@id=…

Linux、Linux操作系统、GUN、GPL

目录 Linux Linux操作系统 GUN GPL Linux 也许很多人会不屑的说&#xff0c;Linux不就是个操作系统么。错&#xff01;Linux不是一个操作系统&#xff0c;严格来讲&#xff0c;Linux只是一个操作系统中的内核。内核是什么&#xff1f;内核建立了计算机软件与硬件之间通讯的平…

python读取大文件的坑_如何在Python中读取大文件的特定部分

Given a large file (hundreds of MB) how would I use Python to quickly read the content between a specific start and end index within the file? Essentially, Im looking for a more efficient way of doing: open(filename).read()[start_index:end_index] 解决方案…

oryx 推荐系统_Cloudera为Hadoop带来机器学习开源工具Oryx

Hadoop发行商Cloudera去年收购伦敦的创业公司Myrrix时&#xff0c;并未引起业界太多关注&#xff0c;其后Cloudera也很少宣传公司在机器学习方面的技术。但是Myrrix的的技术和其创始人Sean Owen在机器学习方面的价值和影响力不容小觑。Owen目前正在开发一个开源机器学习项目——…

POSIX与程序可移植性

目录 一、系统调用和库函数 1、系统调用 2、库函数 二、程序的可移植性及其本质 三、系统开销 四、POSIX 1、定义 2、历史 3、谁来遵循 一、系统调用和库函数 1、系统调用 系统调用是通向操作系统本身的接口&#xff0c;是面向底层硬件的。通过系统调用&#xff0c;可…

python一个函数调用另一个函数的返回值_在另一个函数中使用返回值

所以我认为当你调用check_channel_number函数时&#xff0c;user_channel_number是在那里定义的&#xff0c;所以当你调用delete_events函数时&#xff0c;它已经超出了范围&#xff0c;也许这样会有帮助&#xff1f;user_channel_number check_channel_number() delete_event…

144显示器只有60_你知道显示器60Hz和144Hz的刷新率差别有多大吗?你没有用过吗?...

不知什么时候开始&#xff0c;高刷新率成为了显示器的一个重要卖点&#xff0c;成为了电竞游戏显示器的标配&#xff0c;越来越多的人在购买显示器时&#xff0c;开始抛弃早已定格60Hz刷新率&#xff0c;逐渐向120Hz刷/144Hz刷乃至更高的刷新率上靠拢。那么显示器60Hz和144Hz刷…

linux用户权限不够解析及解决方案

目录 一、用户账户&#xff1a;普通账户、超级账户&#xff08;root&#xff09; 二、组账户&#xff1a;私有组、标准组 三、linux下账户配置文件&#xff1a;passwd、shadow、group、gshadow。 四、文件权限 1、权限分类 2、文件权限含义 3、目录权限含义 四、权限不够…

chmod -R 644 dir04 报错:权限不够

错误截图 错误分析 1、分析当前用户有无对dir04的操作权限 有&#xff0c;dir04的所有者为wlh&#xff0c;wlh的权限为rwx。 2、分析-R是否可以使用空文件夹和文件&#xff0c;而非空文件夹不可以 可能是这样&#xff0c;但是尝试chmod -R 777 dir04成功。所以与非空无关&am…

云桌面部署_东胜区检察院检察工作网统一业务系统2.0云桌面终端全面部署完成...

按照最高检顶层设计和自治区院、市院关于做好统一业务系统2.0版试点应用工作的相关要求&#xff0c;东胜区人民检察院党组高度重视&#xff0c;高标准、高效率、高质量开展部署准备工作&#xff0c;着力保障统一业务应用2.0系统上线后稳、准、快的运行。为按时按要求完成任务&a…

python处理表格数据教程_python利用Excel读取和存储测试数据完成接口自动化教程...

http_request2.py用于发起http请求 #读取多条测试用例 #1、导入requests模块 import requests #从 class_12_19.do_excel1导入read_data函数 from do_excel2 import read_data from do_excel2 import write_data from do_excel2 import count_case #定义http请求函数 COOKIENon…

linux递归参数-R(r)和-p的区别

在linux系统中创建、复制、删除目录或文件时&#xff0c;常常会用到递归参数。常用的递归参数有-p,-r,-P等。为方便初学者学习、分辨与记忆&#xff0c;将其分类整理如下。 一般常用到递归的命令有&#xff1a;mkdir、cp、rm、ls、grep、chmod、chown等。 而mv命令没有递归参…

html table设置行高_字号与行高

1. 什么是字号与行高什么是字号大小&#xff1f;字号大小就是字体的高度&#xff0c;例如设置字号为50px&#xff0c;那么它的高度如下图所示&#xff1a;什么是行距呢&#xff1f;如下图所示&#xff1a;其中半行距 (lineHeight – fontSize) / 2。但是实际上&#xff0c;fon…

linux 用户名为没有名字 报错:cannot find name for user ID

经过一系列用户权限更改后&#xff0c;切换到普通用户&#xff0c;失败&#xff0c;报错如下&#xff1a; 解决方案&#xff1a;这个问题是因为普通用户没有权限读取/etc/passwd和/etc/group文件造成&#xff0c;添加权限即可。 转载自&#xff1a;id: cannot find name for us…

xposed hook 静态函数_浅谈 Xposed 新概念【模块作用域】

众所周知&#xff0c;Xposed 是一个系统级别的软件框架&#xff0c;它与 Cydia Substrate 不同&#xff0c;Xposed 仅可 hook app_process 中的 java 函数&#xff0c;不过对于大部分的 Android 应用来说已经足够了&#xff1b;它所提供的 API 可以供模块开发者在不修改目标应用…

adc0808温度换算公式_温湿度传感器的三种模拟量换算关系

气候的变化常常会导致空气当中的湿度以及温度随之而产生相应的变化&#xff0c;如果想及时感知空气中温湿度的变化&#xff0c;那就需要温湿度传感器。在日常生活中&#xff0c;温湿度传感器种类有很多&#xff0c;按照数据上传方式分有RS485型温湿度传感器、模拟量型温湿度传感…