多线程的控制方式
目录
Condition类相当于一把高级的锁,可以进行一些复杂的线程同步控制。一般Condition内部都有一把内置的锁对象(默认为RLock),对于Condition的使用主要有以下步骤:
- 建立两个线程对象,及Condition对象;
- 线程1首先获取Condition的锁权限,acquire();
- 线程1执行需要完成的任务后,调用等待wait(),此时,线程1会阻塞挂起,出让内置锁的控制权(即Condition可被其他线程acquire);
- 线程2对Condition内置锁的权限进行获取acquire(),当线程2执行需要完成的任务后,会调用唤醒,notify(),但此时线程1并不会立即被唤醒继续执行,而是要等待线程2释放Condition的内置锁release()之后,线程1才会唤醒;
- 线程2释放锁release()之后,线程1自动重新对锁进行占有,直到线程1完成所有任务后,再执行释放锁release(),从而结束。
1 from threading import Thread, Condition 2 import time 3 cond = Condition() 4 5 class Sleeper(Thread): 6 def __init__(self): 7 super(Sleeper, self).__init__() 8 9 def run(self): 10 print('Sleeper gets into room, starts sleeping') 11 cond.acquire() 12 print('Sleeper is sleeping, waiting for wakeup') 13 cond.wait() 14 print('Sleeper is waked up') 15 cond.release() 16 print('Sleeper out of room') 17 18 19 class Waker(Thread): 20 def __init__(self): 21 super(Waker, self).__init__() 22 23 def run(self): 24 print('Waker waiting sleeper getting into room and sleeping...') 25 time.sleep(1) 26 cond.acquire() 27 print('Waker gets into the room') 28 cond.notify() 29 print('Waker trying to wake up sleeper') 30 time.sleep(3) 31 print('Waker finished wake up, leave the room') 32 cond.release() 33 34 sleeper = Sleeper() 35 waker = Waker() 36 sleeper.start() 37 waker.start()
上面的代码中,首先导入所需的模块,生成Condition的实例,之后派生两个线程模拟sleeper和waker,其中sleeper会先对Condition进行获取权限,随后进入等待,而waker会在sleeper进入等待后,获取Condition的权限,然后尝试唤醒sleeper,随后释放Condition锁,将占有权归还,sleeper收到归还的权限后,调用release进行释放。
运行得到结果
Sleeper gets into room, starts sleeping Sleeper is sleeping, waiting for wakeup Waker waiting sleeper getting into room and sleeping... Waker gets into the room Waker trying to wake up sleeper Waker finished wake up, leave the room Sleeper is waked up Sleeper out of room
从输出的结果中可以看到,waker在notify了sleeper之后,等待了3秒,而这三秒内,sleeper并未被彻底唤醒,而是等待waker的release()之后,sleeper才被真正唤醒继续执行。
当有多个线程进入Condition的条件等待时,可以使用两种方式进行唤醒,第一种是利用等数量的线程唤醒,第二种是利用notify_all()函数唤醒所有线程。
下面的例子对比了两种唤醒方式
1 from threading import Thread, Condition 2 import random 3 import time 4 cond = Condition() 5 6 class Sleeper(Thread): 7 def __init__(self): 8 super(Sleeper, self).__init__() 9 self.num = self.name[-1] 10 print('Sleeper_%s ready' % self.num) 11 12 def run(self): 13 print('Sleeper_%s gets into room, starts sleeping' % self.num) 14 cond.acquire() 15 print('Sleeper_%s is sleeping, waiting for wakeup' % self.num) 16 cond.wait() 17 print('Sleeper_%s is waked up' % self.num) 18 cond.release() 19 print('Sleeper_%s out of room' % self.num) 20 21 22 class Waker(Thread): 23 def __init__(self, all=False): 24 super(Waker, self).__init__() 25 self.all = all 26 self.num = self.name[-1] 27 print('Waker_%s ready' % self.num) 28 29 def run(self): 30 print('Waker_%s waiting sleeper getting into room and sleeping...' % self.num) 31 time.sleep(1) 32 cond.acquire() 33 print('Waker_%s gets into the room' % self.num) 34 if self.all: 35 cond.notify_all() 36 else: 37 cond.notify() 38 print('Waker_%s trying to wake up sleeper' % self.num) 39 time.sleep(3) 40 print('Waker_%s finished wake up, leave the room' % self.num) 41 cond.release() 42 43 if __name__ == '__main__': 44 print('-------Order Wake-------') 45 sleepers = [] 46 wakers = [] 47 for i in range(3): 48 sleepers.append(Sleeper()) 49 for i in range(3): 50 wakers.append(Waker()) 51 52 random.shuffle(sleepers) 53 random.shuffle(wakers) 54 55 for s in sleepers: 56 s.start() 57 for s in wakers: 58 s.start() 59 for s in sleepers: 60 s.join() 61 62 print('-------All Wake-------') 63 sleepers = [] 64 for i in range(3): 65 sleepers.append(Sleeper()) 66 waker = Waker(all=True) 67 68 random.shuffle(sleepers) 69 70 for s in sleepers: 71 s.start() 72 waker.start()
上面的代码中,在导入所需模块后,定义Sleeper和Waker类,并让他们拥有各自名字,在主函数中首先利用单个唤醒的方式去唤醒所有线程,随后再利用全部唤醒的方式唤醒所有线程,其中随机数模块用于重新排序Sleeper。
运行得到结果
-------Order Wake------- Sleeper_1 ready Sleeper_2 ready Sleeper_3 ready Waker_4 ready Waker_5 ready Waker_6 ready Sleeper_1 gets into room, starts sleeping Sleeper_1 is sleeping, waiting for wakeup Sleeper_3 gets into room, starts sleeping Sleeper_3 is sleeping, waiting for wakeup Sleeper_2 gets into room, starts sleeping Sleeper_2 is sleeping, waiting for wakeup Waker_4 waiting sleeper getting into room and sleeping... Waker_6 waiting sleeper getting into room and sleeping... Waker_5 waiting sleeper getting into room and sleeping... Waker_6 gets into the room Waker_6 trying to wake up sleeper Waker_6 finished wake up, leave the room Waker_5 gets into the room Waker_5 trying to wake up sleeper Waker_5 finished wake up, leave the room Sleeper_1 is waked up Sleeper_1 out of room Waker_4 gets into the room Waker_4 trying to wake up sleeper Waker_4 finished wake up, leave the room Sleeper_3 is waked up Sleeper_3 out of room Sleeper_2 is waked up Sleeper_2 out of room -------All Wake------- Sleeper_7 ready Sleeper_8 ready Sleeper_9 ready Waker_0 ready Sleeper_9 gets into room, starts sleeping Sleeper_9 is sleeping, waiting for wakeup Sleeper_7 gets into room, starts sleeping Sleeper_7 is sleeping, waiting for wakeup Sleeper_8 gets into room, starts sleeping Sleeper_8 is sleeping, waiting for wakeup Waker_0 waiting sleeper getting into room and sleeping... Waker_0 gets into the room Waker_0 trying to wake up sleeper Waker_0 finished wake up, leave the room Sleeper_9 is waked up Sleeper_9 out of room Sleeper_7 is waked up Sleeper_7 out of room Sleeper_8 is waked up Sleeper_8 out of room