GIL全局解释器锁 1. 什么是GIL全局解释器锁 GIL本质就是一把互斥锁(把多个任务对共享数据的修改,由并发变成串行,牺牲效率保证数据安全),这把互斥锁是阻止多个线程,相当于执行权限,每个进程内都会存在一把GIL,同一进程内的多个线程 必须抢到GIL之后才能使用Cpython解释器来执行自己的代码,即同一进程下的多个线程无法实现并行,但是可以实现并发
在Cpython解释器下,如果想实现并行可以开启多个进程
2. 为何要有GIL 因为Cpython解释器的垃圾回收机制不是线程安全的
3. 如何用GIL 有了GIL,应该如何处理并发 GIL与多线程 1.对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用 2. 多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能 3. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处 我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是: 方案一:开启四个进程 方案二:一个进程下,开启四个线程
#单核情况下,分析结果: 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜 如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
#多核情况下,分析结果: 如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜 如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜
#结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。 举例: from threading import Thread import time
def task(name): print('%s is running'%name) time.sleep(2)
if __name__ == '__main__': t1=Thread(target=task,args=('线程1',)) t2=Thread(target=task,args=('线程1',)) t3=Thread(target=task,args=('线程1',)) t1.start() t2.start() t3.start() 结果: 线程1 is running 线程1 is running 线程1 is running
计算密集型:应该使用多进程 from multiprocessing import Process from threading import Thread import os,time def work(): res=0 for i in range(10000000): res*=i
if __name__ == '__main__': l=[] print(os.cpu_count()) start=time.time() for i in range(4): p=Process(target=work) #3.729213237762451 # p=Thread(target=work) #7.1074066162109375 l.append(p) p.start() for p in l: p.join() stop=time.time() print('run time is %s'%(stop-start)) IO密集型: 应该开启多线程 from multiprocessing import Process from threading import Thread import threading import os,time def work(): time.sleep(2) if __name__ == '__main__': l=[] start=time.time() for i in range(60): # p=Process(target=work) #8.547489166259766 p=Thread(target=work) #2.043116807937622 l.append(p) p.start() for p in l: p.join() stop=time.time() print('run time is %s'%(stop-start))
GIL vs 自定义互斥锁 from threading import Thread,Lock import time
mutex=Lock() n=100 def task(): global n with mutex: temp=n time.sleep(0.1) n=temp-1 if __name__ == '__main__': l=[] for i in range(100): t=Thread(target=task) l.append(t) t.start() for t in l: t.join() print(n) 结果:0
死锁现象与递归锁 from threading import Thread,Lock,RLock import time
# mutexA=Lock() # mutexB=Lock() mutexB=mutexA=RLock()
class Mythead(Thread): def run(self): self.f1() self.f2()
def f1(self): mutexA.acquire() print('%s 抢到A锁' %self.name) mutexB.acquire() print('%s 抢到B锁' %self.name) mutexB.release() mutexA.release()
def f2(self): mutexB.acquire() print('%s 抢到了B锁' %self.name) time.sleep(2) mutexA.acquire() print('%s 抢到了A锁' %self.name) mutexA.release() mutexB.release()
if __name__ == '__main__': for i in range(100): t=Mythead() t.start() 结果: Thread-1 抢到A锁 Thread-1 抢到B锁 Thread-1 抢到了B锁 Thread-1 抢到了A锁 Thread-2 抢到A锁 Thread-2 抢到B锁 Thread-2 抢到了B锁 Thread-2 抢到了A锁 Thread-3 抢到A锁 Thread-3 抢到B锁 Thread-3 抢到了B锁 Thread-3 抢到了A锁 信号量 from threading import Thread,Semaphore import time,random sm=Semaphore(3) def task(name): sm.acquire() print('%s 正在上厕所'%name) time.sleep(random.randint(1,3)) sm.release() if __name__ == '__main__': for i in range(10): t=Thread(target=task,args=('路人%s'%i,)) t.start() 结果: 路人0 正在上厕所 路人1 正在上厕所 路人2 正在上厕所 路人3 正在上厕所 路人5 正在上厕所 路人4 正在上厕所 路人6 正在上厕所 路人7 正在上厕所 路人8 正在上厕所 路人9 正在上厕所 Event事件
from threading import Thread,Event import time event=Event() def light(): print('红灯正亮着') time.sleep(3) event.set() def car(name): print('车%s正在等绿灯'%name) event.wait() print('车%s通行'%name) if __name__ == '__main__': t1=Thread(target=light) t1.start() for i in range(10): t=Thread(target=car,args=(i,)) t.start() 结果: 红灯正亮着 车0正在等绿灯 车1正在等绿灯 车2正在等绿灯 车3正在等绿灯 车4正在等绿灯 车5正在等绿灯 车6正在等绿灯 车7正在等绿灯 车8正在等绿灯 车9正在等绿灯 车2通行 车1通行 车4通行 车3通行 车6通行 车5通行 车8通行 车0通行 车7通行 车9通行 线程queue import queue # queue.Queue() #先进先出 # q=queue.Queue(3) # q.put(1) # q.put(2) # q.put(3) # print(q.get()) # print(q.get()) # print(q.get())
# queue.LifoQueue() #后进先出->堆栈 # q=queue.LifoQueue(3) # q.put(1) # q.put(2) # q.put(3) # print(q.get()) # print(q.get()) # print(q.get()) # queue.PriorityQueue() #优先级 q=queue.PriorityQueue(3) #优先级,优先级用数字表示,数字越小优先级越高 q.put((10,'a')) q.put((-1,'b')) q.put((100,'c')) print(q.get()) print(q.get()) print(q.get()) 结果: 1 2 3 (-1, 'b') (10, 'a') (100, 'c')