day9-GIL、线程锁、递归锁、信号量、event
一、GIL
GIL: 全局解释器锁 无论你启动多少个线程, 你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行 Python线程是调用操作系统的原生线程(C语言编写),因此调用时需要传上下文关系给C(等于加减时要让程序串行才能进行一次运算),一旦调用,python无法控制线程的执行,只能等结果。GIL同一时间只让一个线程拿到数据,避免出错(其他语言没有GIL,仅仅只是CPython有)

二、线程锁(互斥锁)
1 import threading 2 import time 3 4 5 def run(): 6 # 加上线程锁,尽量执行数据少时配置,等于串行 7 lock.acquire() 8 global num 9 num += 1 10 # time.sleep(2) 11 # 释放线程锁 12 lock.release() 13 14 lock = threading.Lock() 15 num = 0 16 # 存线程实例 17 t_obj = [] 18 for i in range(500): 19 t = threading.Thread(target=run, args=()) 20 t.start() 21 # 为了不阻塞后面线程的启动,不在这里join, 先把线程实例放到一个列表 22 t_obj.append(t) 23 24 for obj in t_obj: 25 obj.join() 26 27 print("num: ", num)
多数据共享(不加线程锁Python2可能出现下列情况,据说Python2每执行100条指令切换一次GIL,Python3已优化)流程图:

三、递归锁
原理:递归锁每开一把门,会在字典里面存一份数据,退出的时候根据门(key)找到这个钥匙(value)退出
1 import threading 2 3 4 def run1(): 5 print("grab the part data") 6 # 小门锁 7 lock.acquire() 8 global num 9 num += 1 10 lock.release() 11 return num 12 13 14 def run(): 15 # 大门锁 16 lock.acquire() 17 run1() 18 print('--------run1 done-----') 19 lock.release() 20 21 if __name__ == '__main__': 22 23 num, num2 = 0, 0 24 # 设置全局锁 25 # 全局锁无法处理多个钥匙与锁的对应关系,有递归情况会死锁 26 # lock = threading.Lock() 27 # 设置递归锁 28 lock = threading.RLock() 29 for i in range(1): 30 t = threading.Thread(target=run) 31 t.start() 32 33 # 判断是否只剩主线程 34 while threading.active_count() != 1: 35 print(threading.active_count()) 36 else: 37 print('----all threads done---') 38 print(num, num2)
四、信号量
1 import threading 2 import time 3 4 5 def run(n): 6 # 加信号量 7 # 信号量与线程锁的区别是线程锁只能执行一个线程,信号量可以允许执行多个线程 8 # 在信号量允许的线程数内,执行完一个立即执行下一个,并非把线程分组执行完一轮再执行下一轮的线程 9 # python不会默认启动多少进程,但启动线程越多,就会把系统拉得越慢,程序执行越慢 10 semaphore.acquire() 11 time.sleep(1) 12 print("run the thread: %s\n" % n) 13 # 释放信号量 14 semaphore.release() 15 16 if __name__ == '__main__': 17 # 最多允许5个线程同时运行 18 semaphore = threading.BoundedSemaphore(5) 19 for i in range(22): 20 t = threading.Thread(target=run, args=(i,)) 21 t.start() 22 23 while threading.active_count() != 1: 24 print threading.active_count() 25 else: 26 print('----all threads done---')
五、event
1 import time 2 import threading 3 4 5 # 设置事件全局变量 6 event = threading.Event() 7 8 9 def lighter(): 10 """ 11 红绿灯 12 :return: 13 """ 14 count = 0 15 # 设置标志位,代表绿灯 16 event.set() 17 while True: 18 # 绿灯5秒后变为红灯,红灯5秒后变为绿灯 19 if 5 <= count < 10: 20 # 清除标志位,代表红灯 21 event.clear() 22 print("\033[41mred light is on ....\033[0m") 23 elif count > 10: 24 # 创建标志位,变为绿灯 25 event.set() 26 count = 0 27 else: 28 print("\033[44;1mgreen light is on ....\033[0m") 29 30 time.sleep(1) 31 count += 1 32 33 34 def car(name): 35 """ 36 车子 37 :param name: 38 :return: 39 """ 40 while True: 41 # 有标志位,代表绿灯 42 if event.is_set(): 43 print("{0} running ....".format(name)) 44 time.sleep(1) 45 # 没有标志位,代表红灯 46 else: 47 print("{0} sees red light ,waiting ....".format(name)) 48 # 等待 49 event.wait() 50 print("\033[32mgreen light is on , start going ...\033[0m") 51 52 # 没有参数可以不写args 53 light = threading.Thread(target=lighter,) 54 light.start() 55 56 for i in range(5): 57 carname = "car" + str(i) 58 carobj = threading.Thread(target=car, args=(carname,)) 59 carobj.start()

浙公网安备 33010602011771号