GIL
GIL锁: 全局解释器锁. Cpython特有的一把互斥锁,自动加锁解锁将并发变成串行同一时刻同一进程中只有一个线程被执行使用共享资源 ,牺牲效率,保证数据安全.
同一个进程中的多个线程只能有一个线程真正被cpu执行
设置全局解释锁: GIL
- 保证解释器里面的数据安全.
当时开发py语言时,只有单核, - 强行加锁: 减轻了你开发的人员的负担.
单个进程多线程不能利用多核,为什么不去掉?
不能去掉,源码太多,改不动了
不能用多核会影响效率吗
看处理数据情况
我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是: 方案一:开启四个进程 方案二:一个进程下,开启四个线程 #单核情况下,分析结果: 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜 如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜 #多核情况下,分析结果: 如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜 如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜 #结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。
总结:
多核的前提下: 如果任务Io密集型: 多线程并发.
如果任务计算密集型: 多进程并发
GIL锁与互斥锁的关系.
GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理
# 互斥锁 保护用户自己的数据则需要自己加锁处理 自己加互斥锁,一定要加在处理共享数据的地方,加的范围不要扩大, # 1. GIL 自动上锁解锁, 文件中的互斥锁Lock 手动上锁解锁. # 2. GIL锁 保护解释器的数据安全. 文件的互斥锁Lock 保护的文件数据的安全.
什么是池
# 要在程序开始的时候,还没提交任务先创建固定数量的进程或线程 放在一个池子里,这就是池
为什么要用池?
# 如果先开好进程/线程,那么有任务之后就可以直接使用这个池中的数据了 # 并且开好的线程或者进程会一直存在在池中 处理完毕进程并不关闭,可以被多个任务反复利用 # 这样极大的减少了开启\关闭\调度线程/进程的时间开销 # 池中的线程/进程个数控制了操作系统需要调度的任务个数,控制池中的单位 # 有利于提高操作系统的效率,减轻操作系统的负担
multiprocess.Poll模块 ThreadPoolExecutor(4)#起进程或线程第个数 我一般cpu个数加1 from concurrent.futures import ProcessPoolExecutor from concurrent.futures import ThreadPoolExecutor import time import os import random def task(name): print(name) print(f'{os.getpid()} 准备接客') time.sleep(random.randint(1,3)) if __name__ == '__main__': p = ThreadPoolExecutor() # ,默认cpu数量*5 for i in range(23): p.submit(task,1) # 给进程池放任务,传参
面试题
线程池好,进程池好?
答题思路 多线程,多进程.: IO 计算