20190103(GIL,池,阻塞,同步异步)
GIL锁
什么是GIL
GIL全局解释器锁,是防止多个线程在同一时间同时执行的、CPython解释器特有的一种互斥锁。 每一个py文件都会有自己的解释器,也就是说不同py文件的GIL都是独立的, ps:分散于不同进程内的线程不会去争抢同一把GIL,只有同一个进程的多个线程才争抢同一把GIL。
为什么需要GIL
CPython解释器的内存管理机制是非线程安全的,所以通过GIL使程序串行,可以保证数据安全,但会降低执行效率。 非线程安全属于历史遗留问题,而一旦修改,原来基于GIL的程序都要修改。
GIL带来的问题
即便多核处理器,也无法真正并行(可以并发),进程内线程只能并发,同一时刻只有一个线程可以运行
GIL的加锁和解锁时机(待补充)
加锁的时机:在调用解释器时立即加锁
解锁时机:
当前线程遇到了IO时释放
当前线程执行时间超过设定值时释放,解释器会检测线程的执行时间,一旦到达某个阈值,通知线程保存状态切换线程,以此来保证数据安全
多进程与多线程的使用情况分析:
1、单核时,无论是IO密集还是计算密集,GIL都没有影响; 2、多核下,IO密集型会受到GIL的影响,但是影响不大,此时优先考虑多线程处理数据; 3、多核下,计算密集型受到GIL影响较大,此时使用多进程可以提高效率,因为CPython多线程无法并行,但多进程可以。
程序运行时间对比:
# 纯计算,大量,进程更快(如果只是少量计算,线程未必慢,因为开启进程比开启线程更费时间)
from threading import Thread
from multiprocessing import Process
import time
a = 1
def task():
global a
for i in range(10000000):
a +=1
a * 10 / 2 - 3
# 多线程
s = time.time()
t1 = Thread(target=task)
t2 = Thread(target=task)
t3 = Thread(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(time.time()-s)
# 多进程
if __name__ == '__main__':
s = time.time()
t1 = Process(target=task)
t2 = Process(target=task)
t3 = Process(target=task)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(time.time()-s)
GIL与自定义互斥锁的异同
GIL作用于全局,自定义互斥锁作用于局部 线程必须先获取GIL才能去拿自定义互斥锁 单进程内的所有线程都会去抢GIL 单进程内的只有一部分线程会去抢自定义的互斥锁
进程池与线程池
是一种容器,本质是储存进程或线程的列表 IO密集使用线程池,计算密集使用进程池 线程/进程池不仅帮我们控制线程/进程的数量,还帮我们完成了线程/进程的创建,销毁,以及任务的分配
池与信号量的区别:
信号量的作用是同一时间某一个数据能被指定数量的进程或线程访问 而池控制的是数量,没有对数据访问进行限制
进程池:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os
# 创建进程池,指定最大进程数为3,此时不会创建进程,不指定数量时,默认为CPU核数
pool = ProcessPoolExecutor(3)
def task():
time.sleep(1)
print(os.getpid(),"working..")
if __name__ == '__main__':
for i in range(10):
pool.submit(task) # 提交任务时立即创建进程
# 任务执行完成后也不会立即销毁进程
time.sleep(2)
for i in range(10):
pool.submit(task) #再有新任务时 直接使用之前已经创建好的进程来执行
输出结果:(每次可能都不同)
13760 working..
26536 working..
21388 working..
13760 working..
26536 working..
21388 working..
26536 working..
13760 working..
21388 working..
26536 working..
13760 working..
21388 working..
13760 working..
26536 working..
21388 working..
13760 working..
26536 working..
21388 working..
13760 working..
26536 working..
线程池:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread,active_count
import time,os
# 创建进程池,指定最大线程数为3,此时不会创建线程,不指定数量时,默认为CPU和核数*5
pool = ThreadPoolExecutor(3)
print(active_count()) # 只有一个主线
def task():
time.sleep(1)
print(current_thread().name,"working..")
for i in range(10):
pool.submit(task) # 第一次提交任务时立即创建线程
# 任务执行完成后也不会立即销毁
time.sleep(2)
for i in range(10):
pool.submit(task) #再有新任务是 直接使用之前已经创建好的线程来执行
阻塞vs非阻塞
阻塞、就绪、运行指的是进程的三种执行状态。 阻塞=》遇到io操作,无法继续执行,并且立刻释放CPU资源 非阻塞=》正常执行中(就绪、运行),没有遇到IO操作,或者通过某种手段让程序即便遇到IO也不会停在原地,而是执行其他操作。
总结:阻塞与非阻塞指的是程序的执行状态
同步与异步
同步与异步:指的是提交任务的两种方式
同步(调用/执行/任务/提交):提交完任务后就在原地等待,拿到返回值后才能继续执行下一行代码(可能是IO,也可能是因为计算时间较长等原因)。 异步(调用/执行/任务/提交):提交完任务后不在原地等待,不关心任务的结果,直接执行下一行代码。
异步效率高于同步。
异步提交任务时,任务可能包含IO操作,异步也可能阻塞。 同步提交任务时,也可能会因为计算复杂而卡,不等同与阻塞。
程序中的异步调用并获取结果:
from concurrent.futures import ThreadPoolExecutor # 导入线程池
from threading import current_thread # 从线程中导入查看当前线程的方法
import time
pool = ThreadPoolExecutor(3)
def task(i):
time.sleep(0.01)
print(current_thread().name,"working..")
return i ** i
objs = []
for i in range(1,5):
res_obj = pool.submit(task,i) # 异步方式提交任务,会返回一个对象用于表示任务结果,即pool.submit()会生成对象
objs.append(res_obj)
pool.shutdown(wait=True) # shutdown是一个阻塞函数,指的是不能再往进程池内提交任务,wait=True等待进程池或线程池内所有的任务都运行完毕,才允许代码往下继续执行。
# 从结果对象中取出执行结果
for res_obj in objs: # 从列表中拿出对象
print(res_obj.result()) # 由submit得到的对象会有result()方法,即对象内封装的返回值
print("over")
程序中的同步调用并获取结果:(等到返回结果才能继续执行)
from concurrent.futures import ThreadPoolExecutor
import time,random
def task(i):
print("%s run"%i)
time.sleep(random.randint(1,3))
return i**2 # 返回值,这也是result方法的要求。
pool = ThreadPoolExecutor(3)
for i in range(6):
p = pool.submit(task,i)
res = p.result()
print(res)
print("over")
输出结果:
0 run
0
1 run
1
2 run
4
3 run
9
4 run
16
5 run
25
over
20190103(GIL,池,阻塞,同步异步)的更多相关文章
- python GIL锁、进程池与线程池、同步异步
一.GIL全局解释器锁 全局解释器锁 在CPython中,全局解释器锁(GIL)是一个互斥锁,它可以防止多个本机线程同时执行Python代码.之所以需要这个锁,主要是因为CPython的内存管理不是线 ...
- GIL锁、进程池与线程池、同步异步
GIL锁定义 GIL锁:Global Interpreter Lock 全局解释器 本质上是一把互斥锁 官方解释: 在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同 ...
- python 之 并发编程(进程池与线程池、同步异步阻塞非阻塞、线程queue)
9.11 进程池与线程池 池子使用来限制并发的任务数目,限制我们的计算机在一个自己可承受的范围内去并发地执行任务 池子内什么时候装进程:并发的任务属于计算密集型 池子内什么时候装线程:并发的任务属于I ...
- 进程(并发,并行) join start 进程池 (同步异步)
一.背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象.进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有 ...
- 进程理论 阻塞非阻塞 同步异步 I/O操作
1.什么是进程 进程指的是一个正在运行的程序,进程是用来描述程序执行过程的虚拟概念 进程的概念起源于操作系统,进程是操作系统最核心的概念,操作系统其它所有的概念都是围绕进程来的 2.操作系统 操作系统 ...
- 阻塞 , 非阻塞 , 同步 ,异步 , I/O模型
•阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待: •同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞:异步只需要I/O操作完成的通知,并不主动读写 ...
- nio 阻塞 非阻塞 同步 异步
https://mp.weixin.qq.com/s/5SKgdkC0kaHN495psLd3Tg 说在前面 上篇NIO相关基础篇二,主要介绍了文件锁.以及比较关键的Selector,本篇继续NIO相 ...
- python 管道 事件(Event) 信号量 进程池(map/同步/异步)回调函数
####################总结######################## 管道:是进程间通信的第二种方式,但是不推荐使用,因为管道会导致数据不安全的情况出现 事件:当我运行主进程的 ...
- GIL全局解释器锁,线程池与进程池 同步异步,阻塞与非阻塞,异步回调
GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents ...
- GIL 线程池 进程池 同步 异步
1.GIL(理论 重点)2.线程池 进程池3.同步 异步 GIL 是一个全局解释器锁,是一个互斥锁 为了防止竞争解释器资源而产生的 为何需要gil:因为一个python.exe进程中只有一份解释器,如 ...
随机推荐
- 解决Spring JdbcTemplate调用queryForObject()方法结果集为空时报异常
JdbcTemplate用的时候发现一个问题:调用queryForObject()方法,如果没有查到东西则会抛一个异常:org.springframework.dao.EmptyResultDataA ...
- linux下的rpm软件包,rpm源码包和tar安装包
Linux下的软件包是一个独立的程序,用于Linux系统的包管理.在Linux下,软件包的安装方式很多样,不如Windows下的软件安装简单,Windows下基本上就是傻瓜式下一步下一步,而Linux ...
- WCF SecurityElement
1.SslStreamSecurityElement <sslStreamSecurity requireClientCertificate="true"/> Requ ...
- $.ajax和$.load的区别
http://lib.csdn.net/article/jquery/35614?knId=646
- cf1042F. Leaf Sets(贪心)
题意 题目链接 给出一棵树,删除一些边,使得任意联通块内的任意点距离不超过$k$ sol 考场上想的贪心是对的:考虑一棵子树,如果该子树内最深的两个节点的距离相加$>k$就删掉最深的那个点,向上 ...
- 解决IE8的兼容问题
本文分享下我在项目中积累的IE8+兼容性问题的解决方法.根据我的实践经验,如果你在写HTML/CSS时候是按照W3C推荐的方式写的,然后下面的几点都关注过,那么基本上很大一部分IE8+兼容性问题都OK ...
- linux中python安装
1.查看当前环境中是否存在python安装包 [zyj@localhost ~]$ rpm -qa | grep python gnome-python2-gnome--.el6.x86_64 pyt ...
- MySQL访问
MySQL访问 1.介绍 python访问mysql数据库,需要安装mysql的python插件. 2.安装插件 通过pip命令安装mysql插件. # cmd>pip install PyMy ...
- kubernetes发布解释型语言应用的最佳实践
说明 k8s在发布编译型语言的应用时,几乎不用多考虑,就会选择将编译好jar/war包(java语言)或者二进制文件(golang/c++)直接打到镜像当中,生成新的应用镜像,然后将镜像推到镜像仓库, ...
- linux下安装和卸载mysql
卸载: 1 . rpm -qa | grep -i mysql命令查看已经安装过的组件. 2. 使用yum -y remove命令卸载已经安装的MySQL组件,使用下面的命令,对于上面已经安装 ...