python的多线程+GIL全局解释器锁+其他LOCK

---恢复内容开始---

python的多线程实际上只有一个线程。

为了让各个线程能够平均利用CPU时间,python会计算当前已执行的微代码数量,达到一定阈值后就强制释放GIL。而这时也会触发一次操作系统的线程调度(当然是否真正进行上下文切换由操作系统自主决定)。

 

GIL全局解释器锁: 保证同一时间只有一个线程得到数据并且只有一个线程执行,但是cpu调度时间到了以后,第一个线程无论是否完成均程等待状态(若未执行完毕,数据放入寄存器中)下一线程得到的依旧是原始的公共数据。

用户级lock:保证同一时间只有一个线程在修改数据。(可以避免几个线程同时对公共原始数据进行修改,提高线程效率)

为公共数据Lock:一个线程修改后,释放,下一进程才可再次进行修改。

 

RLock(递归锁):在一个大锁中还要再包含子锁

 1 import threading, time
 2 
 3 
 4 def run1():
 5     print("grab the first part data")
 6     lock.acquire()
 7     global num
 8     num += 1
 9     lock.release()
10     return num
11 
12 
13 def run2():
14     print("grab the second part data")
15     lock.acquire()
16     global num2
17     num2 += 1
18     lock.release()
19     return num2
20 
21 
22 def run3():
23     lock.acquire()
24     res = run1()
25     print('--------between run1 and run2-----')
26     res2 = run2()
27     lock.release()
28     print(res, res2)
29 
30 
31 # if __name__ == '__main__':
32 
33 num, num2 = 0, 0
34 lock = threading.RLock()
35 for i in range(10):
36     t = threading.Thread(target=run3)
37     t.start()
38 
39 while threading.active_count() != 1:
40     print(threading.active_count())
41 else:
42     print('----all threads done---')
43     print(num, num2)

线程锁(互斥锁Mutex)


信号量:和单个锁的区别是信号量有多个锁

 1 import threading, time
 2 
 3 # 信号量就是多个锁
 4 def run(n):
 5     semaphore.acquire()#信号量获取
 6     time.sleep(1)
 7     print("run the thread: %s\n" % n)
 8     semaphore.release() # 信号量释放
 9 
10 
11 if __name__ == '__main__':
12 
13     num = 0
14     semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
15     for i in range(20):
16         t = threading.Thread(target=run, args=(i,))
17         t.start()
18 
19 while threading.active_count() != 1:
20     pass  # print threading.active_count()
21 else:
22     print('----all threads done---')
23     print(num)

 

事件Event:实现红绿灯

概念&涉及知识点:

事件是一个简单的同步对象;代表一个内部标志,线程可以等待设置标志,或者自己设置或清除标志。

#客户端线程可以等待设置标志      event.wait()

#a服务器线程可以设置或重置它     event.set()  event.clear()

如果设置了标志,则wait方法不会执行任何操作。
如果该标志被清除,则等待将被阻塞,直到它再次被设置为止。
任意数量的线程都可以等待同一事件。

 1 import time
 2 import  threading
 3 
 4 event = threading.Event()
 5 def Lighter():
 6     count = 0
 7     event.set()
 8     while True:
 9         if count >5 and count <10: # 改成红灯
10             #无标志位会显示等待,有标志位是通行。  wait是通行
11             event.clear() #清空标志位
12             print('\033[41;1mred light \033[0m')
13         elif count >10:
14             event.set() # 设置标志位,变绿灯
15             count = 0
16         else:
17             print('\033[42;1mgreen light \033[0m')
18 
19         time.sleep(1)
20         count += 1
21 
22 def car(name):
23     while True:
24         if event.is_set(): #代表绿灯
25             time.sleep(1)
26             print('[%s] running '%name)
27         else:
28             print('[%s] sees red light ,waiting '%name)
29             event.wait()
30             print('\033[34;1m[%s] green light is on ,start going \033[0m'%name)
31 
32 light = threading.Thread(target=Lighter,)
33 light.start()
34 
35 car1 = threading.Thread(target=car,args=('Car1',))
36 car1.start()

 

队列:使程序之间实现松耦合,提高处理效率。

两种模式:

 FIFO = first in first out

 LIFO = last in first out

队列和列表的区别:

队列:数据取出后,队列中就没有此数据了。

列表;数据取出进行操作,但是列表中仍旧有原数据。

 

生产者与消费者模式(做解耦):

 1 import threading,time
 2 
 3 import queue
 4 
 5 q = queue.Queue()
 6 q.maxsize = 10
 7 
 8 def Producer(name):
 9     count = 1
10     #for i in range(10):
11     while True:
12         q.put("骨头%s" %count) #%i)
13         print("生产了骨头",count)
14         count += 1
15         time.sleep(2)
16 
17 
18 def Consumer(name):
19     while True:
20         print("[%s]取到[%s]并且吃了它" %(name, q.get()))
21         time.sleep(1)
22 
23 p = threading.Thread(target=Producer, args=("lex",))
24 c1 = threading.Thread(target=Consumer, args=("chen",))
25 c2 = threading.Thread(target=Consumer, args=("wang",))
26 
27 p.start()
28 c1.start()
29 c2.start()

 

posted @ 2019-07-19 14:07  菠菜猫  阅读(370)  评论(0编辑  收藏  举报