python-day36--并发编程之多线程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-day36--并发编程之多线程相关的知识,希望对你有一定的参考价值。

十三、死锁、递归锁

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

技术分享
 1 from threading import Lock,Thread
 2 import time
 3 mutexB=Lock()
 4 mutexA=Lock()
 5 class MyThread(Thread):
 6     def run(self):
 7         self.f1()
 8         self.f2()
 9 
10     def f1(self):
11         mutexA.acquire()
12         print(%s拿到了A锁 %self.name)
13         mutexB.acquire()
14         print(%s拿到了B锁 %self.name)
15         mutexB.release()
16         mutexA.release()
17 
18     def f2(self):
19         mutexB.acquire()
20         print(%s拿到了B锁 %self.name)
21         time.sleep(1)
22         mutexA.acquire()
23         print(%s拿到了A锁 %self.name)
24         mutexA.release()
25         mutexB.release()
26 
27 if __name__ == __main__:
28     for i in range(10):
29         t=MyThread()
30         t.start()
31 
32 # 结果
33 # Thread-1拿到了A锁
34 # Thread-1拿到了B锁
35 # Thread-1拿到了B锁
36 # Thread-2拿到了A锁
37 。。。。 卡住了
View Code

  2.解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

技术分享
 1 from threading import Thread,RLock
 2 import time
 3 mutexB=mutexA=RLock()
 4 class MyThread(Thread):
 5     def run(self):
 6         self.f1()
 7         self.f2()
 8 
 9     def f1(self):
10         mutexA.acquire()
11         print(\033[32m%s 拿到A锁 %self.name)
12         mutexB.acquire()
13         print(\033[45m%s 拿到B锁 %self.name)
14         mutexB.release()
15         mutexA.release()
16 
17     def f2(self):
18         mutexB.acquire()
19         print(\033[32m%s 拿到B锁 %self.name)
20         time.sleep(1)
21         mutexA.acquire()
22         print(\033[45m%s 拿到A锁 %self.name)
23         mutexA.release()
24         mutexB.release()
25 
26 if __name__ == __main__:
27     for i in range(2):
28         t=MyThread()
29         t.start()
30 
31 # 结果:
32 # Thread-1 拿到A锁
33 # Thread-1 拿到B锁
34 # Thread-1 拿到B锁
35 # Thread-1 拿到A锁
36 # Thread-2 拿到A锁
37 # Thread-2 拿到B锁
38 # Thread-2 拿到B锁
39 # Thread-2 拿到A锁
View Code

十四、信号量Semaphore

  Semaphore管理一个内置的计数器,
  每当调用acquire()时内置计数器-1;
  调用release() 时内置计数器+1;
  计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

技术分享
 1 from threading import Thread,Semaphore,currentThread
 2 import time,random
 3 sm=Semaphore(5)    #限制最大连接数为5
 4 def task():
 5     sm.acquire()
 6     print(%s 上厕所 %currentThread().getName())
 7     time.sleep(random.randint(1,3))
 8     print(%s 走了 %currentThread().getName())
 9     sm.release()
10 if __name__ == __main__:
11     for i in range(20):
12         t=Thread(target=task)
13         t.start()
View Code

  与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,而且从头到尾都只是这    四个进程,不会产生新的,而信号量是产生一堆线程/进程

十五、Event事件

1 event.isSet():返回event的状态值;
2 
3 event.wait():如果 event.isSet()==False将阻塞线程;
4 
5 event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
6 
7 event.clear():恢复event的状态值为False。
技术分享
 1 from threading import Thread,Event,currentThread
 2 import time
 3 e=Event()
 4 
 5 def traffic_lights():
 6     time.sleep(5)
 7     e.set()
 8 
 9 def car():
10     print(\033[45m%s 等 %currentThread().getName())
11     e.wait()
12     print(\033[45m%s 跑 %currentThread().getName())
13 
14 
15 if __name__ == __main__:
16     for i in range(10):
17         t=Thread(target=car)
18         t.start()
19     traffic_thread=Thread(target=traffic_lights)
20     traffic_thread.start()
例子
技术分享
 1 from threading import Thread,Event,currentThread
 2 import time
 3 e=Event()
 4 def conn_mysql():
 5     count=1
 6     while not e.is_set():
 7         if count > 3:
 8             raise ConnectionError(尝试链接的次数过多)
 9         print(\033[45m%s 第%s次尝试 %(currentThread().getName(),count))
10         e.wait(timeout=1)
11         count+=1
12     print(\033[45m%s 开始链接 %currentThread().getName())
13 
14 def check_mysql():
15     print(\033[45m%s 检测mysql... %currentThread().getName())
16     time.sleep(4)     #超时了
17     e.set()
18 if __name__ == __main__:
19     t=Thread(target=check_mysql)
20     t.start()
21     for i in range(3):
22         t=Thread(target=conn_mysql)
23         t.start()
重要的例子

十六、定时器

技术分享
1 from threading import Timer
2 
3 def hello(n):
4     print("hello, world",n)
5 
6 t = Timer(3, hello,args=(123,))   #3秒后运行hello函数, 可以传参数
7 t.start()
View Code

十七、线程queue

  queue队列 :使用import queue,用法与进程Queue一样

  queue.Queue      #先进先出   #队列

技术分享
 1 import queue
 2 
 3 q=queue.Queue()
 4 q.put(first)
 5 q.put(second)
 6 q.put(third)
 7 
 8 print(q.get())
 9 print(q.get())
10 print(q.get())
11 ‘‘‘
12 结果(先进先出):
13 first
14 second
15 third
16 ‘‘‘
View Code

  queue.LifoQueue     #last in fisrt out  #堆栈

技术分享
 1 import queue
 2 
 3 q=queue.LifoQueue()
 4 q.put(first)
 5 q.put(second)
 6 q.put(third)
 7 
 8 print(q.get())
 9 print(q.get())
10 print(q.get())
11 ‘‘‘
12 结果(后进先出):
13 third
14 second
15 first
16 ‘‘‘
View Code

  queue.PriorityQueue     #存储数据时可设置优先级的队列

技术分享
 1 import queue
 2 
 3 q=queue.PriorityQueue()
 4 #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
 5 q.put((20,a))
 6 q.put((10,b))
 7 q.put((30,c))
 8 
 9 print(q.get())
10 print(q.get())
11 print(q.get())
12 ‘‘‘
13 结果(数字越小优先级越高,优先级高的优先出队):
14 (10, ‘b‘)
15 (20, ‘a‘)
16 (30, ‘c‘)
17 ‘‘‘
View Code

 




以上是关于python-day36--并发编程之多线程的主要内容,如果未能解决你的问题,请参考以下文章

Java面试之多线程

Java面试之多线程

python并发编程之多线程

python学习40——并发编程之多线程

python并发编程之多线程

并发编程之多线程之间通讯