GIL,queue,进程池与线程池
GIL
1.什么是GIL(这是Cpython解释器)
GIL本质就是一把互斥锁,既然是互斥锁,原理都是一样的,都是让多个并发线程同一时间只能有一个执行
即:有了GIL的存在,同一进程内的多个线程同一时刻只能有一个在运行,意味着Cpython中一个进程下的多个线程无法实现并行,所以就无法利用多核优势,但不影响并发的实现
GIL可以被比喻成执行权限,同一进程下的所有线程,想要执行都需要先抢执行权限
2.为何要有GIL
因为Cpython解释器自带垃圾回收机制不是线程安全的
3.如何用
GIL vs 自定义互斥锁
GIL相当于执行权限,会在任务无法执行的情况下,被强行释放
自定义互斥锁即便是无法执行,也不会自动释放
4.有两种并发解决方案:
多进程:计算密集型
多线程:IO密集型
线程queue
#1.队列:先进先出 q=queue.Queue(3) q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get()) #2.堆栈:先进后出 q=queue.LifoQueue() q.put(1) q.put(2) q.put(3) print(q.get()) print(q.get()) print(q.get()) #3. 优先级队列:优先级高先出来,数字越小,优先级越高 q=queue.PriorityQueue() q.put((3,'data1')) q.put((-10,'data2')) q.put((11,'data3')) print(q.get()) print(q.get()) print(q.get())
进程池与线程池
1.什么时候用池
池的功能是限制启动的进程或线程数
什么时候应该限制?
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时,就应该使用池的概念,将开启的进程数或线程数限制在计算机可承受的范围内。
2.同步vs异步
同步、异步指的是提交任务的两种方式
同步:提交任务后就在原地等待,直到任务运行完毕后拿到任务的返回值,再继续运行下一行代码
异步:提交完任务(绑定一个回调函数)后根本就不在原地等待,直接运行下一行代码,等到任务有返回值后会自动触发回调函数
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor import os,time,random def task(n): print('%s run...' %os.getpid()) time.sleep(5) return n**2 def parse(future): time.sleep(1) res=future.result() print('%s 处理了 %s' %(os.getpid(),res)) if __name__ == '__main__': pool=ProcessPoolExecutor(4) start=time.time() for i in range(1,5): future=pool.submit(task,i) future.add_done_callback(parse) # parse会在futrue有返回值时立刻触发,并且将future当作参数传给parse pool.shutdown(wait=True) stop=time.time() print('主',os.getpid(),(stop - start))
线程池只需要将pool=ProcessPoolExecutor(4)改成pool = ThreadPoolExecutor(4)即可,在使用回调时,多进程是用主进程来执行回调的,而多线程是哪个线程闲着就由哪个线程来执行