python theading线程开发与加锁、信号量、事件等详解

线程有2种调用方式,如下:

直接调用

 1 import threading
 2 import time
 3  
4 def sayhi(num): #定义每个线程要运行的函数 6 print("running on number:%s" %num) 8 time.sleep(3) 9 10 if __name__ == '__main__': 12 t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例 13 t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例 15 t1.start() #启动线程 16 t2.start() #启动另一个线程 18 print(t1.getName()) #获取线程名 19 print(t2.getName())

继承式调用

import threading
import time
 
class MyThread(threading.Thread): def __init__(self,num): threading.Thread.__init__(self) self.num = num def run(self):#定义每个线程要运行的函数 print("running on number:%s" %self.num) time.sleep(3) if __name__ == '__main__': t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start()

同步锁(py2版本) *注:不要在3.x上运行,不知为什么,3.x上的结果总是正确的,可能是自动加了锁

 1 import time
 2 import threading
 3 
 4 
 5 def addNum():
 6     global num  # 在每个线程中都获取这个全局变量
 7     print('--get num: %s' %num)
 8     time.sleep(1)
 9     lock.acquire()  # 修改数据前加锁
10     num -= 1  # 对此公共变量进行-1操作
11     lock.release()  # 修改后释放
12 
13 num = 100  # 设定一个共享变量
14 thread_list = []
15 lock = threading.Lock() #生成全局锁
16 for i in range(100):
17     t = threading.Thread(target=addNum)
18     t.start()
19     print "threading num: %s 
" %threading.active_count()  #查看线程数
20     thread_list.append(t)
21 
22 for t in thread_list:  # 等待所有线程执行完毕
23     t.join()
24 
25 print('final num:', num)

死锁

所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程成为死锁进程。

 1 import threading
 2 import time
 3 
 4 mutexA = threading.Lock()
 5 mutexB = threading.Lock()
 6 
 7 class MyThread(threading.Thread):
 8     def __init__(self):
 9         threading.Thread.__init__(self)
10 
11     def run(self):
12         self.fun1()
13         self.fun2()
14 
15     def fun1(self):
16         mutexA.acquire()
17         print("fun1 I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
18 
19         mutexB.acquire()#线程2卡在这里,获取不到锁B,线程2此时已经有锁A
20         print("fun1 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 
21         mutexB.release()
22         print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time()))
23         mutexA.release()
24         print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time()))
25 
26     def fun2(self):
27         mutexB.acquire()
28         print("fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time()))
29 
30         time.sleep(0.3) #这里整个进程sleep,
31         print("sleep fun2 I am %s,get res:%s---%s" % (self.name, "ResB", time.time())) 
32 
33         mutexA.acquire()#线程1卡在这一步,线程1此时已经有锁b
34         print("fun2 I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
35 
36         mutexA.release()
37         print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResA", time.time()))
38 
39         mutexB.release()
40         print("FUN1 I am %s, release res:%s---%s" % (self.name, "ResB", time.time()))
41 
42 
43 if __name__ == '__main__':
44     print("start------------%s", time.time())
45     for i in range(0, 10): #一次循环,代表一个线程
46         print "%s 
" %i
47         my_thread = MyThread()
48         my_thread.start()
运行结果

0

fun1 I am Thread-1,get res:ResA---1551263063.35       #线程1获得锁B
fun1 I am Thread-1,get res:ResB---1551263063.35       #线程1获得锁B
FUN1 I am Thread-1, release res:ResB---1551263063.35  #线程1释放锁B
FUN1 I am Thread-1, release res:ResA---1551263063.35  #线程1释放锁A
fun2 I am Thread-1,get res:ResB---1551263063.35       #线程1获得锁B

1

fun1 I am Thread-2,get res:ResA---1551263063.35       #线程2释放锁A

2

..

9

sleep fun2 I am Thread-1,get res:ResB---1551263065.35 #线程2释放锁B

总结:

   1、线程1已有B锁,准备获取A锁

   2、线程2已有A锁,准备获取B锁

   1和2同一时刻,因此互相等待

RLock(递归锁)

说白了就是在一个大锁中还要再包含子锁

在python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

 1 Rlock = threading.RLock()
 2 class MyThread(threading.Thread):
 3     def __init__(self):
 4         threading.Thread.__init__(self)
 5 
 6     def run(self):
 7         self.fun1()
 8         self.fun2()
 9 
10     def fun1(self):
11         Rlock.acquire()  # 如果锁被占用,则阻塞在这里,等待锁的释放
12         print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
13         Rlock.acquire()  # count=2
14         print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time()))
15 
16         Rlock.release()  # count-1
17         Rlock.release()  # count-1=0
18 
19     def fun2(self):
20         Rlock.acquire()  # count=1
21         print("I am %s,get res:%s---%s" % (self.name, "ResB", time.time()))
22         time.sleep(0.2)
23 
24         Rlock.acquire()  # count=2
25         print("I am %s,get res:%s---%s" % (self.name, "ResA", time.time()))
26         Rlock.release()  # coun-1
27         Rlock.release()  # count-1
28 
29 
30 if __name__ == '__main__':
31     print("start-----------%s" % time.time())
32     for i in range(0, 10):
33         my_thread = MyThread()
34         my_thread.start()

Semaphore(信号量)

原理:来限制一个时间点内的线程数量。比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

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

Events

通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

红绿灯

 1 import threading,time
 2 import random
 3 def light():
 4     if not event.isSet():
 5         event.set() #wait就不阻塞 #绿灯状态
 6     count = 0
 7     while True:
 8         if count < 10:
 9             print('33[42;1m--green light on---33[0m')
10         elif count <13:
11             print('33[43;1m--yellow light on---33[0m')
12         elif count <20:
13             if event.isSet():
14                 event.clear()
15             print('33[41;1m--red light on---33[0m')
16         else:
17             count = 0
18             event.set() #打开绿灯
19         time.sleep(1)
20         count +=1
21 def car(n):
22     while 1:
23         time.sleep(random.randrange(10))
24         if  event.isSet(): #绿灯
25             print("car [%s] is running.." % n)
26         else:
27             print("car [%s] is waiting for the red light.." %n)
28 if __name__ == '__main__':
29     event = threading.Event()
30     Light = threading.Thread(target=light)
31     Light.start()
32     for i in range(3):
33         t = threading.Thread(target=car,args=(i,))
34         t.start()

员工过门禁

 1 import threading
 2 import time
 3 import random
 4 
 5 def door():
 6     door_open_time_counter = 0
 7     while True:
 8         if door_swiping_event.is_set():
 9             print("33[32;1mdoor opening....33[0m")
10             door_open_time_counter +=1
11         else:
12             print("33[31;1mdoor closed....,please swipe to open.33[0m")
13             door_open_time_counter = 0 #清空计时器
14             door_swiping_event.wait()
15         if door_open_time_counter > 3:#门开了已经3s了,该关了
16             door_swiping_event.clear()
17         time.sleep(0.5)
18 
19 def staff(n):
20     print("staff [%s] is comming..." % n )
21     while True:
22         if door_swiping_event.is_set():
23             print("33[34;1mdoor is opened, staff [%s] passing.....over!!33[0m" % n )
24             break
25         else:
26             print("STAFF [%s] sees door got closed, swipping the card....." % n)
27             door_swiping_event.set()
28             print("after set,,,  staff [%s]--------" %n,door_swiping_event.is_set())
29         # time.sleep(0.5)
30 
31 door_swiping_event  = threading.Event() #设置事件
32 door_thread = threading.Thread(target=door)
33 door_thread.start()
34 for i in range(5):
35     p = threading.Thread(target=staff,args=(i,))
36     time.sleep(random.randrange(3))
37     p.start()
运行结果
door closed....,please swipe to open.
staff [0] is comming...
STAFF [0] sees door got closed, swipping the card.....
('after set,,,  staff [0]--------', True)
door is opened, staff [0] passing.....over!!
door opening....
door opening....
door opening....
door opening....
staff [1] is comming...
STAFF [1] sees door got closed, swipping the card.....
('after set,,,  staff [1]--------'staff [2] is comming..., 
Truedoor is opened, staff [2] passing.....over!!)

door is opened, staff [1] passing.....over!!
door opening....
door closed....,please swipe to open.
staff [3] is comming...
STAFF [3] sees door got closed, swipping the card.....
('after set,,,  staff [3]--------', True)
door is opened, staff [3] passing.....over!!
door opening....
door opening....
staff [4] is comming...
door is opened, staff [4] passing.....over!!
door opening....
door opening....
door closed....,please swipe to open.
原文地址:https://www.cnblogs.com/kevincaptain/p/10445048.html