GIL锁、进程池与线程池、同步异步
GIL锁定义
GIL锁:Global Interpreter Lock 全局解释器
本质上是一把互斥锁
官方解释:
在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同一时间执行Python字节码,
这个锁是非常重要的,因为CPython的内存管理是非线程安全的,也有很多其他的特性依赖于GIL(比如有些
东西是依赖这个GIL写好的,要替换成本很高),所以即使它影响了程序的效率,也无法直接将其去除。
需要知道的是,解释器并不只有CPython,还有PyPy,Jpython等等,GIL仅存在于Cpython中,这并不是Python
这们语言的问题,而是CPython解释器的问题
GIL解决的问题
执行py文件的三个步骤
1.从硬盘加载python解释器到内存
2.从硬盘加载py文件到内存
3.解释器解析py文件内容,交给cpu执行
并且,每当执行一个py文件,就会立即启动一个python解释器
解释器的作用
py文件中的内容本质都是字符串,cpu无法执行,只有当字符串被解释器解释成python字节码的时候,
才能被cpu执行起来,所以,对于一个进程来说,同时只能有一个线程被解释器执行
内存管理机制
对于python而言,我们是不需要手动去清除垃圾的,因为python中有一个垃圾回收机制
垃圾回收机制的原理是依据引用计数
a = 10 内存中10的地址计数为1
b = a 10的计数变为2
b = 1 10的计数变为1
a = 1 10的计数变为0
当垃圾回收启动后,会将计数为0的数据清除掉,回收内存(占着内存没有计数的称为内存泄漏)
产生的问题
垃圾回收机制本质上也是一串代码,也是需要被解释器解释执行
所以对于一个开启的进程而言
不仅有你执行py文件的一个线程,还有着向垃圾回收机制这样的线程
当多个线程同时并发执行的时候,就会产生一个问题,就是两条线程同时访问统一资源带来的数据错乱问题
例如:
主线程定义一个变量,刚使用解释器被cpu执行到开辟空间的时候,引用计数还没有变成1,然后cpu切走了
然后垃圾回收线程被唤醒了,并且解释器切换到它使用,他一看内存空间有引用计数为0的,就清除了
当主线程再切回来的时候就懵逼了
GIL如何解决
GIL会给解释器上一把锁,当一条线程使用解释器的时候,其他线程无法使用解释器,
解释器会在cpu切走之前,切换线程,并且会保存上一个线程的一些状态,保证不会被其他线程修改
这样就让一个系统资源的一个安全性得到保障
GIL带来的问题
问题
由于这个GIL的锁的问题,就导致在同一个进程中,多个线程只能并发执行,并不能做到并行执行
所以在计算密集型的问题上,CPython的速度要慢于其他高级编程
为什么要这么设计
CPython诞生于1991年,多核处理器诞生于2004年,
所以在CPython诞生的时候,本来就不行并行执行,所以在当时加锁的处理是基本完美的
为什么拿掉这个锁的设计,在这个期间,很多已经完成的代码都是依赖GIL锁完成的
如果直接拿掉,代码得重新修改,成本太大
GIL锁的加锁与解锁时机
加锁:当一个线程使用解释器时,就立马加锁
释放:
1、该线程任务结束
2、该线程遇到IO操作
3、该线程使用解释器过程 默认100纳秒(一般比cpu的时间片短)
关于GIL的性能讨论
GIL的优点:
保证了CPython中的内存管理是线程安全的
GIL的缺点:
互斥锁的特性使得多线程无法并行
但我们并不能因此否认Python这门语言,原因如下:
1、GIL仅仅在CPython解释器中存在,在其他解释器中没有,并不是Python这门语言的缺点
2、在单核处理器下,多线程之间本来就无法真正的并行执行
3、在多核处理器下,运算效率的却是比单核处理器高,但要知道现代应用程序多数都是基于网络的
CPU无法决定网络速度的,当IO操作比较多的时候,多核也需要等待IO操作完成,优势就没那么明显了
总结:
1、单核状态下,无论是IO密集还是计算密集型GIL都不会产生任何影响(本来就只能并发)
2、多核情况下对于IO密集型任务,GIL会有细微的影响,基本可以忽略
3、CPython中IO密集任务应该采用多线程,计算密集型应该采用多进程
自定义的线程锁与GIL的区别
相同点:都是互斥锁
不同点:GIL锁锁的是解释器内部的资源,例如引用计数,分带回收数据等等,
但并不能保证我们自定义数据资源的安全性
所以我们自己开启的共享资源还得自己加锁,保证资源的安全
进程池与线程池
池 就是容器,
进程池:装进程的容器
线程池:装线程的容器
好处
1、自动管理线程的开启和销毁
2、自动分配任务给空闲的线程
3、可以限制开启线程的数量,保证系统的稳定
在这里需要注意的是:这里的限制数量和信号量中的控制并发数量不一样,这里限制的是开启
线程的最大数量(线程可能还没开启),但是信号量中的线程已经全部开启,控制并发量
如何使用
1、创建池子
2、submit提交任务
3、pool.shutdown() # 等待所有任务全部完毕,销毁所有线程后关闭线程池(主线程需要等待)
from concurrent.futures import ThreadPoolExecutor # 导入类 pool = ThreadPoolExecutor() # 实例化产生池子对象 def task(name):
# 代码区
print(name)
pass pool.submit(task,"rock") pool.shutdown() # 可以让主线程等待线程池里的任务全部完毕,才往下执行
同步异步
在并发编程中,经常提及到的名词:阻塞非阻塞,并行并发,同步异步
阻塞非阻塞
指的是程序的运行状态,程序运行有三个状态:阻塞态、运行态、就绪态
阻塞指的是阻塞态 非阻塞可能是运行态或者是就绪态
并发并行
指的是多任务状态下处理任务的方式
并发:多个任务看起来像在同时运行,本质上是切换+保存状态
并行:真正的同时执行,必须具备多核处理器
同步异步
指的是任务提交的方式
同步:指的是任务发起后,必须在原地等待任务完成,拿到结果,才能接着往下执行,
这就称之为同步,默认的情况就是同步
注意:协程也是同步
异步:指的是任务发起后,不需要再原地等待,可以接着执行其他代码,称之为异步
异步任务必须依赖并发或者并行 再python中通过多进程、多线程实现
异步可以一起执行代码,效率明显高于同步
需要注意的是:
1、同步不等于阻塞:同步虽然需要在原地等待,但是提交的任务可能一直在运行,那就不是阻塞
2、卡住不等于阻塞:原因同上
3、异步不等于非阻塞:提交完任务后,如果两边都遇到了IO操作,那就阻塞了
异步回调
异步指的是任务提交的方式是异步的
异步出现的问题
如果这个任务需要返回值,我需要拿到返回值处理结果,那么该什么时候去拿返回值
如果早了,任务还未完成;如果晚了,那么结果就没有得到及时处理
解决方案
异步回调
异步回调指的就是一个函数,该函数会在任务完成后自动被调用,并且会把一个Future对象传进去(任务对象)
通过Future对象的result()获取执行结果
import time
from concurrent.futures import ThreadPoolExecutor # 导入类 pool = ThreadPoolExecutor() # 实例化产生池子对象 def task(): # 任务函数
print("task run")
time.sleep(2)
print("task over")
return "执行结果" # 返回结果 def call_back(obj): # 回调函数,调用会自动把Future对象传进去,所以在这需要接收一下
res = obj.result() # 通过result() 拿到结果
print(res) p = pool.submit(task) # 创建一个Future对象 <Future at 0x200d73230f0 state=running>
p.add_done_callback(call_back) # Future对象有个方法添加回调函数
# 这样提交完任务后不仅会被及时处理,而且还不需要等待,可以接着执行其他代码
通常异步任务都会绑定一个回调函数,用来处理任务结果
在进程池中,回调函数是在父进程中执行的,进程间数据不共享,需要把数据返回来
在线程池中,回调函数是由当前执行的线程发起执行的,同一进程中的线程共享资源,可以直接运行
GIL锁、进程池与线程池、同步异步的更多相关文章
- GIL锁、进程池与线程池
1.什么是GIL? 官方解释: ''' In CPython, the global interpreter lock, or GIL, is a mutex that prevents multip ...
- GIL解释锁及进程池和线程池
官方介绍 ''' 定义: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple nati ...
- day37 GIL、同步、异步、进程池、线程池、回调函数
1.GIL 定义: GIL:全局解释器锁(Global Interpreter Lock) 全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码 为什么需要全局解释器锁 在我们进行代码编写时,实 ...
- GIL全局解释器锁、死锁现象、python多线程的用处、进程池与线程池理论
昨日内容回顾 僵尸进程与孤儿进程 # 僵尸进程: 所有的进程在运行结束之后并不会立刻销毁(父进程需要获取该进程的资源) # 孤儿进程: 子进程正常运行 但是产生该子进程的父进程意外死亡 # 守护进程: ...
- GIL解释器锁 & 进程池与线程池
今日内容 GIL 全局解释器锁(重要理论) 验证 GIL 的存在及功能 验证 python 多线程是否有用 死锁现象 进程池与线程池(使用频率高) IO模型 详细参考: https://www.bil ...
- 4月27日 python学习总结 GIL、进程池、线程池、同步、异步、阻塞、非阻塞
一.GIL:全局解释器锁 1 .GIL:全局解释器锁 GIL本质就是一把互斥锁,是夹在解释器身上的, 同一个进程内的所有线程都需要先抢到GIL锁,才能执行解释器代码 2.GIL的优缺点: 优点: 保 ...
- GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程
GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- GIL,queue,进程池与线程池
GIL 1.什么是GIL(这是Cpython解释器) GIL本质就是一把互斥锁,既然是互斥锁,原理都是一样的,都是让多个并发线程同一时间只能有一个执行 即:有了GIL的存在,同一进程内的多个线程同一时 ...
随机推荐
- ISO/IEC 9899:2011 条款6.2.5——类型
6.2.5 类型 1.存储在一个对象中的值或由一个函数所返回的值的意义由用于访问该对象的表达式的类型来确定.(声明为一个对象的一个标识符是最简单的这种表达式:其类型在标识符的声明中指定.)类型被划分为 ...
- 002-创建型-04-建造者模式(Builder)、JDK1.7源码中的建造者模式、Spring中的建造者模式
一.概述 建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象 ...
- java导入excel很完美的取值的方法
java导入excel很完美的取值的方法 1.解决方法: /** * 获取单元格数据内容为字符串类型的数据 * @param cell Excel单元格 * @return St ...
- 第五章 编码/加密——《跟我学Shiro》
转发地址:https://www.iteye.com/blog/jinnianshilongnian-2021439 目录贴:跟我学Shiro目录贴 在涉及到密码存储问题上,应该加密/生成密码摘要存储 ...
- Linux 学习笔记 1 使用最小的系统,从分区安装系统开始
我们常用的linux系统在安装过程中大多都省略了对系统进行分区的操作,以至于后期,不了解什么是分区以及分区当中最基本的一些概念, 我们不说最细的知识,只求了解这个过程,那直接步入正题,开始第一节的学习 ...
- java中创建线程的方式
创建线程的方式: 继承thread 实现runnable 线程池 FurureTask/Callable 第一种:继承thread demo1: public class demo1 { public ...
- springboot与shiro在html中使用shiro标签
上一章讲环境搭建 springboot与shiro和mybatis和mysql 现在讲html中怎么使用shiro标签,这里是基于上一章讲的 在pom文件引入依赖 <dependency> ...
- SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题
原文链接:https://segmentfault.com/a/1190000012879279 当前后端分离时,权限问题的处理也和我们传统的处理方式有一点差异.笔者前几天刚好在负责一个项目的权限管理 ...
- Java程序的编写与执行、Java新手常见问题及解决方法|乐字节Java学习
今天,我们来写一段Java程序.然后看看Java程序是如何执行的,以及Java新手小白遇到的问题和解决办法. 一.HelloWorld的编写 ① 新建一个XXX.java (文件的扩展名显示出来) ...
- Python基础——循环语句、条件语句、函数、类
注:运行环境 Python3 1.循环语句 (1)for循环 注:for i in range(a, b): #从a循环至b-1 for i in range(n): #从0循环至n-1 ...