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()

 

posted @ 2017-11-11 14:46  不知所以  阅读(113)  评论(0)    收藏  举报