Python2.7 Queue模块学习

最近接触一个项目,要在多个虚拟机中运行任务,参考别人之前项目的代码,采用了多进程来处理,于是上网查了查python中的多进程

一、先说说Queue(队列对象)

Queue是python中的标准库,可以直接import 引用,之前学习的时候有听过著名的“先吃先拉”与“后吃先吐”,其实就是这里说的队列,队列的构造的时候可以定义它的容量,别吃撑了,吃多了,就会报错,构造的时候不写或者写个小于1的数则表示无限多

import Queue

q = Queue.Queue(10)

向队列中放值(put)

q.put(‘yang’)

q.put(4)

q.put([‘yan’,’xing’])

在队列中取值get()

默认的队列是先进先出的

>>> q.get() 
'yang' 
>>> q.get() 

>>> q.get() 
['yan', 'xing'] 
>>>

 

当一个队列为空的时候如果再用get取则会堵塞,所以取队列的时候一般是用到

get_nowait()方法,这种方法在向一个空队列取值的时候会抛一个Empty异常

所以更常用的方法是先判断一个队列是否为空,如果不为空则取值

队列中常用的方法

Queue.qsize() 返回队列的大小  
Queue.empty() 如果队列为空,返回True,反之False  
Queue.full() 如果队列满了,返回True,反之False 
Queue.get([block[, timeout]]) 获取队列,timeout等待时间  
Queue.get_nowait() 相当Queue.get(False) 
非阻塞 Queue.put(item) 写入队列,timeout等待时间  
Queue.put_nowait(item) 相当Queue.put(item, False)

 

二、multiprocessing中使用子进程概念

from multiprocessing import Process

可以通过Process来构造一个子进程

p = Process(target=fun,args=(args))

再通过p.start()来启动子进程

再通过p.join()方法来使得子进程运行结束后再执行父进程

 
  1. from multiprocessing import Process

  2. import os

  3.  
  4. # 子进程要执行的代码

  5. def run_proc(name):

  6. print 'Run child process %s (%s)...' % (name, os.getpid())

  7.  
  8. if __name__=='__main__':

  9. print 'Parent process %s.' % os.getpid()

  10. p = Process(target=run_proc, args=('test',))

  11. print 'Process will start.'

  12. p.start()

  13. p.join()

  14. print 'Process end.'

image

三、在multiprocessing中使用pool

如果需要多个子进程时可以考虑使用进程池(pool)来管理

from multiprocessing import Pool

 

 
  1. from multiprocessing import Pool

  2. import os, time

  3.  
  4. def long_time_task(name):

  5. print 'Run task %s (%s)...' % (name, os.getpid())

  6. start = time.time()

  7. time.sleep(3)

  8. end = time.time()

  9. print 'Task %s runs %0.2f seconds.' % (name, (end - start))

  10.  
  11. if __name__=='__main__':

  12. print 'Parent process %s.' % os.getpid()

  13. p = Pool()

  14. for i in range(5):

  15. p.apply_async(long_time_task, args=(i,))

  16. print 'Waiting for all subprocesses done...'

  17. p.close()

  18. p.join()

  19. print 'All subprocesses done.'

pool创建子进程的方法与Process不同,是通过

p.apply_async(func,args=(args))实现,一个池子里能同时运行的任务是取决你电脑的cpu数量,如我的电脑现在是有4个cpu,那会子进程task0,task1,task2,task3可以同时启动,task4则在之前的一个某个进程结束后才开始

image

上面的程序运行后的结果其实是按照上图中1,2,3分开进行的,先打印1,3秒后打印2,再3秒后打印3

代码中的p.close()是关掉进程池子,是不再向里面添加进程了,对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。

当时也可以是实例pool的时候给它定义一个进程的多少

如果上面的代码中p=Pool(5)那么所有的子进程就可以同时进行

三、多个子进程间的通信

多个子进程间的通信就要采用第一步中说到的Queue,比如有以下的需求,一个子进程向队列中写数据,另外一个进程从队列中取数据,

 

 
  1. #coding:gbk

  2.  
  3. from multiprocessing import Process, Queue

  4. import os, time, random

  5.  
  6. # 写数据进程执行的代码:

  7. def write(q):

  8. for value in ['A', 'B', 'C']:

  9. print 'Put %s to queue...' % value

  10. q.put(value)

  11. time.sleep(random.random())

  12.  
  13. # 读数据进程执行的代码:

  14. def read(q):

  15. while True:

  16. if not q.empty():

  17. value = q.get(True)

  18. print 'Get %s from queue.' % value

  19. time.sleep(random.random())

  20. else:

  21. break

  22.  
  23. if __name__=='__main__':

  24. # 父进程创建Queue,并传给各个子进程:

  25. q = Queue()

  26. pw = Process(target=write, args=(q,))

  27. pr = Process(target=read, args=(q,))

  28. # 启动子进程pw,写入:

  29. pw.start()

  30. # 等待pw结束:

  31. pw.join()

  32. # 启动子进程pr,读取:

  33. pr.start()

  34. pr.join()

  35. # pr进程里是死循环,无法等待其结束,只能强行终止:

  36. print

  37. print '所有数据都写入并且读完'

 

四、关于上面代码的几个有趣的问题

 
  1. if __name__=='__main__':

  2. # 父进程创建Queue,并传给各个子进程:

  3. q = Queue()

  4. p = Pool()

  5. pw = p.apply_async(write,args=(q,))

  6. pr = p.apply_async(read,args=(q,))

  7. p.close()

  8. p.join()

  9.  
  10. print

  11. print '所有数据都写入并且读完'

 

 

如果main函数写成上面的样本,本来我想要的是将会得到一个队列,将其作为参数传入进程池子里的每个子进程,但是却得到

RuntimeError: Queue objects should only be shared between processes through inheritance

的错误,查了下,大意是队列对象不能在父进程与子进程间通信,这个如果想要使用进程池中使用队列则要使用multiprocess的Manager类

 
  1. if __name__=='__main__':

  2. manager = multiprocessing.Manager()

  3. # 父进程创建Queue,并传给各个子进程:

  4. q = manager.Queue()

  5. p = Pool()

  6. pw = p.apply_async(write,args=(q,))

  7. time.sleep(0.5)

  8. pr = p.apply_async(read,args=(q,))

  9. p.close()

  10. p.join()

  11.  
  12. print

  13. print '所有数据都写入并且读完'

 

这样这个队列对象就可以在父进程与子进程间通信,不用池则不需要Manager,以后再扩展multiprocess中的Manager类吧

关于锁的应用,在不同程序间如果有同时对同一个队列操作的时候,为了避免错误,可以在某个函数操作队列的时候给它加把锁,这样在同一个时间内则只能有一个子进程对队列进行操作,锁也要在manager对象中的锁

 
  1. #coding:gbk

  2.  
  3. from multiprocessing import Process,Queue,Pool

  4. import multiprocessing

  5. import os, time, random

  6.  
  7. # 写数据进程执行的代码:

  8. def write(q,lock):

  9. lock.acquire() #加上锁

  10. for value in ['A', 'B', 'C']:

  11. print 'Put %s to queue...' % value

  12. q.put(value)

  13. lock.release() #释放锁

  14.  
  15. # 读数据进程执行的代码:

  16. def read(q):

  17. while True:

  18. if not q.empty():

  19. value = q.get(False)

  20. print 'Get %s from queue.' % value

  21. time.sleep(random.random())

  22. else:

  23. break

  24.  
  25. if __name__=='__main__':

  26. manager = multiprocessing.Manager()

  27. # 父进程创建Queue,并传给各个子进程:

  28. q = manager.Queue()

  29. lock = manager.Lock() #初始化一把锁

  30. p = Pool()

  31. pw = p.apply_async(write,args=(q,lock))

  32. pr = p.apply_async(read,args=(q,))

  33. p.close()

  34. p.join()

  35.  
  36. print

  37. print '所有数据都写入并且读完'

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zy205817/article/details/51388479

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的queue模块提供了多种队列实现,包括FIFO(先进先出)队列、LIFO(后进先出)队列和优先级队列。这些队列都是线程安全的,可以在多线程环境下使用。 queue模块中最常用的类是Queue类,它实现了一个FIFO队列。Queue类提供了以下方法: 1. put(item, block=True, timeout=None):将item放入队列中。如果block为True(默认值),并且队列已满,则阻塞直到有空间可用。如果timeout不为None,则阻塞timeout秒,如果还是没有空间可用,则抛出Queue.Full异常。 2. get(block=True, timeout=None):从队列中取出一个元素并返回。如果block为True(默认值),并且队列为空,则阻塞直到有元素可用。如果timeout不为None,则阻塞timeout秒,如果还是没有元素可用,则抛出Queue.Empty异常。 3. qsize():返回队列中的元素个数。 4. empty():如果队列为空,返回True,否则返回False。 5. full():如果队列已满,返回True,否则返回False。 除了Queue类,queue模块还提供了LifoQueue类和PriorityQueue类。LifoQueue类实现了一个LIFO队列,PriorityQueue类实现了一个优先级队列,其中元素按照优先级从小到大排序。 下面是一个使用Queue类的例子: ```python import queue import threading def worker(q): while True: item = q.get() if item is None: break print(item) q.task_done() q = queue.Queue() num_worker_threads = 4 threads = [] for i in range(num_worker_threads): t = threading.Thread(target=worker, args=(q,)) t.start() threads.append(t) for item in range(20): q.put(item) q.join() for i in range(num_worker_threads): q.put(None) for t in threads: t.join() ``` 这个例子中,我们创建了一个Queue对象,并启动了4个线程来处理队列中的元素。主线程向队列中放入20个元素,然后等待队列中的所有元素都被处理完毕。最后,主线程向队列中放入4个None元素,以通知工作线程退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值