python并发队列_Python的并发并行[2] -> 队列[1] -> 使用队列进行任务控制

使用队列进行任务控制

1 FIFO与LIFO队列

FIFO(First In First Out)与LIFO(Last In First Out)分别是两种队列形式,在FIFO中,满足先入先出的队列方式,而LIFO则是后入先出的队列形式,利用这两种方式可以实现不同的队列功能。

1 from random importrandint2 from time importsleep, ctime3 from queue importQueue, LifoQueue4 from threading importThread5

6 COUNT =07

8

9 classMyThread(Thread):10 """

11 Bulid up a Module to make this subclass more general12 And get return value by add a function named 'getResult()'13 """

14 def __init__(self, func, args, name=''):15 Thread.__init__(self)16 self.name =name17 self.func =func18 self.args =args19

20 defgetResult(self):21 returnself.res22

23 defrun(self):24 print('Starting', self.name, 'at:', ctime())25 #Call function here and calculate the running time

26 self.res = self.func(*self.args)27 print(self.name, 'finished at:', ctime())28

29

30 classMyQueue():31 def __init__(self):32 self.funcs =[self.writer, self.reader]33 self.nfuncs =range(len(self.funcs))34

35 defwriteQ(self, queue):36 globalCOUNT37 print('Producing object OBJ_%d for Q...' % COUNT, end=' ')38 queue.put('OBJ_%d' %COUNT, True)39 print('size now:', queue.qsize())40 COUNT += 1

41

42 defreadQ(self, queue):43 #If queue is empty, block here until queue available

44 val =queue.get(True)45 print('Consumed object %s from Q... size now:' %val, queue.qsize())46

47 defwriter(self, queue, loops):48 for i inrange(loops):49 self.writeQ(queue)50 sleep(randint(1, 3))51

52 defreader(self, queue, loops):53 for i inrange(loops):54 self.readQ(queue)55 sleep(randint(2, 5))56

57 defmain(self):58 nloops = randint(2, 5)59 fifoQ = Queue(32)60 lifoQ = LifoQueue(32)61

62 #First In First Out mode for Queue

63 print('-----Start FIFO Queue-----')64 threads =[]65 for i inself.nfuncs:66 threads.append(MyThread(self.funcs[i], (fifoQ, nloops), self.funcs[i].__name__))67 for t inthreads:68 t.start()69 for t inthreads:70 t.join()71 #Last In First Out mode for LifoQueue

72 print('-----Start LIFO Queue-----')73 threads =[]74 for i inself.nfuncs:75 threads.append(MyThread(self.funcs[i], (lifoQ, nloops), self.funcs[i].__name__))76 for t inthreads:77 t.start()78 for t inthreads:79 t.join()80

81 print('All DONE')82

83 if __name__ == '__main__':84 MyQueue().main()

第 1-27 行,首先对需要的模块进行导入,并定义一个全局变量的计数器,派生一个MyThread线程类,用于调用函数及其返回值(本例中MyThread可用于接受writer和reader函数,同时将Queue的实例作为参数传给这两个函数)。

第 30-79 行,定义一个队列类,用于进行队列一系列处理,其中writeQ与readQ会分别对队列执行put和get函数,在writeQ中利用全局变量设置每个加入队列的对象的名字。而writer和reader则会利用循环多次执行writeQ和readQ函数。最后定义一个main函数,用于生成队列,同时调用FIFO以及LIFO两种队列方式。

运行得到结果

-----Start FIFO Queue-----Starting writer at: Tue Aug1 21:43:22 2017Producing object OBJ_0for Q... size now: 1Starting reader at: Tue Aug1 21:43:22 2017Consumed object OBJ_0fromQ... size now: 0

Producing object OBJ_1for Q... size now: 1Producing object OBJ_2for Q... size now: 2Producing object OBJ_3for Q... size now: 3Consumed object OBJ_1from Q... size now: 2writer finished at: Tue Aug1 21:43:26 2017Consumed object OBJ_2from Q... size now: 1Consumed object OBJ_3fromQ... size now: 0

reader finished at: Tue Aug1 21:43:34 2017

-----Start LIFO Queue-----Starting writer at: Tue Aug1 21:43:34 2017Producing object OBJ_4for Q... size now: 1Starting reader at: Tue Aug1 21:43:34 2017Consumed object OBJ_4fromQ... size now: 0

Producing object OBJ_5for Q... size now: 1Producing object OBJ_6for Q... size now: 2Producing object OBJ_7for Q... size now: 3writer finished at: Tue Aug1 21:43:38 2017Consumed object OBJ_7from Q... size now: 2Consumed object OBJ_6from Q... size now: 1Consumed object OBJ_5fromQ... size now: 0

reader finished at: Tue Aug1 21:43:53 2017All DONE

View Code

从输出可以看出,FIFO满足先入先出,LIFO满足后入先出的队列形式。

2 join挂起与task_done信号

在queue模块中,Queue类提供了两个用于跟踪监测任务完成的函数,join和task_done,对于join函数来说,当Queue的类实例调用了join函数挂起时,join函数会阻塞等待,一直到join之前进入队列的所有任务全部标记为task_done后才会解除阻塞。

Note: 通过查看Queue的源码可以看出,在调用put函数时,会对类变量unfinished_tasks进行数值加1,而调用get函数时并不会将unfinished_tasks进行减1,只有调用task_done函数才会导致变量减1。而调用join函数时,join函数会对这个unfinished_tasks变量进行获取,也就是说,join函数会获取到在调用之前所有被put进队列里的任务中,还没有调用过task_done函数的任务数量,无论这个任务是否已经被get出列。

下面的例子中,以Queue_FIFO_LIFO.py中的MyQueue为基类,派生出一个新类,用于测试join函数与task_done函数。

1 from Queue_FIFO_LIFO import *

2

3 classNewQueue(MyQueue):4 def __init__(self):5 MyQueue.__init__(self)6

7 defwriter(self, queue, loops):8 for i inrange(loops):9 self.writeQ(queue)10 sleep(randint(1, 3))11 print('Producing join here, waiting consumer')12 queue.join()13

14 defreader(self, queue, loops):15 for i inrange(loops):16 self.readQ(queue)17 sleep(randint(2, 5))18 print('OBJ_%d task done' %i)19 queue.task_done()20

21 defmain(self):22 nloops = randint(2, 5)23 fifoQ = Queue(32)24

25 print('-----Start FIFO Queue-----')26 threads =[]27 for i inself.nfuncs:28 threads.append(MyThread(self.funcs[i], (fifoQ, nloops), self.funcs[i].__name__))29 for t inthreads:30 t.start()31 for t inthreads:32 t.join()33

34 print('All DONE')35

36 if __name__ == '__main__':37 NewQueue().main()

上面的代码,在导入模块后,调用MyQueue的初始化函数进行初始化设置。在新类NewQueue中,对原基类的writer和reader以及main方法进行了重载,加入了join函数和task_done函数,并在main函数中只采用FIFO队列进行试验。

运行得到结果

-----Start FIFO Queue-----Starting writer at: Wed Aug2 09:06:40 2017Producing object OBJ_0for Q... size now: 1Starting reader at: Wed Aug2 09:06:40 2017Consumed object OBJ_0fromQ... size now: 0

Producing object OBJ_1for Q... size now: 1Producing object OBJ_2for Q... size now: 2OBJ_0 task done

Consumed object OBJ_1from Q... size now: 1Producing object OBJ_3for Q... size now: 2Producing object OBJ_4for Q... size now: 3Producing join here, waiting consumer

OBJ_1 task done

Consumed object OBJ_2from Q... size now: 2OBJ_2 task done

Consumed object OBJ_3from Q... size now: 1OBJ_3 task done

Consumed object OBJ_4fromQ... size now: 0

OBJ_4 task done

reader finished at: Wed Aug2 09:07:02 2017writer finished at: Wed Aug2 09:07:02 2017All DONE

View Code

通过得到的结果可以看出,当新类里的writer完成了自己的Producing任务后,会由join挂起,一直等待直到reader的Consuming全部完成且标记task_done之后,才会解除挂起,此时writer和reader将会一起结束退出。

相关阅读

参考链接

《Python 核心编程 第3版》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值