python基础--GIL全局解释器锁、Event事件、信号量、死锁、递归锁
ps:python解释器有很多种,最常见的就是C python解释器
GIL全局解释器锁:
GIL本质上是一把互斥锁:将并发变成串行,牺牲效率保证了数据的安全
用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)
GIL的存在是因为C python解释器的内存管理不是线程安全的
垃圾回收机制:
1、引用计数
2、标记清除
3、分代回收
研究python 的多线程是否有用的话需要分情况讨论:
同时执行四个任务 计算密集型:10s
# 计算密集型 from multiprocessing import Process from threading import Thread #mport os,time def work(): res=0 for i in range(100000000): res*=i if __name__ == '__main__': l=[] print(os.cpu_count()) # 本机为6核 start=time.time() for i in range(6): # p=Process(target=work) #耗时 4.732933044433594 p=Thread(target=work) #耗时 22.83087730407715 l.append(p) p.start() for p in l: p.join() stop=time.time() print('run time is %s' %(stop-start))
单核情况下:
开线程更节省资源
多核情况下:
开进程:10s
开线程:40s
同时执行四个IO密集型任务
# IO密集型 from multiprocessing import Process from threading import Thread import threading import os,time def work(): time.sleep(2) if __name__ == '__main__': l=[] print(os.cpu_count()) #本机为6核 start=time.time() for i in range(4000): p=Process(target=work) #耗时9.001083612442017s多,大部分时间耗费在创建进程上 # p=Thread(target=work) #耗时2.051966667175293s多 l.append(p) p.start() for p in l: p.join() stop=time.time() print('run time is %s' %(stop-start))
单核:开线程更省资源
多核:开线程更省资源
Event事件:
from threading import Event,Thread import time # 先生成一个event对象 e = Event() def light(): print('红灯正亮着') time.sleep(3) e.set() # 发信号 print('绿灯亮了') def car(name): print('%s正在等红灯'%name) e.wait() # 等待信号 print('%s加油门飙车了'%name) t = Thread(target=light) t.start() for i in range(10): t = Thread(target=car,args=('伞兵%s'%i,)) t.start()
信号量:在不同的领域中,对应不同的知识点
互斥锁:一个厕所(一个坑)
信号量:公共厕所(多个坑位)
from threading import Semaphore,Thread import time import random sm = Semaphore(5) # 造了一个含有五个的坑位的公共厕所 def task(name): sm.acquire() print('%s占了一个坑位'%name) time.sleep(random.randint(1,3)) sm.release() for i in range(40): t = Thread(target=task,args=(i,)) t.start()
死锁:
RLock可以被第一个抢到锁的人连续的acquire和release
每acquire一次锁身上的计数就加1
每release一次锁身上的计数就减1
只要是锁的计数不为0 其他人都不能抢
class MyThread(Thread): def run(self): # 创建线程自动触发run方法 run方法内调用func1 func2相当于也是自动触发 self.func1() self.func2() def func1(self): mutexA.acquire() print('%s抢到了A锁'%self.name) # self.name等价于current_thread().name mutexB.acquire() print('%s抢到了B锁'%self.name) mutexB.release() print('%s释放了B锁'%self.name) mutexA.release() print('%s释放了A锁'%self.name) def func2(self): mutexB.acquire() print('%s抢到了B锁'%self.name) time.sleep(1) mutexA.acquire() print('%s抢到了A锁' % self.name) mutexA.release() print('%s释放了A锁' % self.name) mutexB.release() print('%s释放了B锁' % self.name) for i in range(10): t = MyThread() t.start()
递归锁:
import threading class MyThread(threading.Thread): def run(self): global n1, n2 lock.acquire() # 加锁 n1 += 1 print(self.name + ' set n1 to ' + str(n1)) lock.acquire() # 再次加锁 n2 += n1 print(self.name + ' set n2 to ' + str(n2)) lock.release() lock.release() n1, n2 = 0, 0 lock = threading.RLock() if __name__ == '__main__': thread_list = [] for i in range(5): t = MyThread() t.start() thread_list.append(t) for t in thread_list: t.join() print('final num:%d ,%d' % (n1, n2))