python多处理问题

时间:2015-04-16 16:52:17

标签: python process queue multiprocessing

我在使用进程和队列时遇到了一些问题。

当我运行以下代码时,目标函数只是从主队列中获取一个项目,并将其添加到特定于该进程的另一个队列中。

import sys
import multiprocessing
from Queue import Empty

# This is just taking a number from the queue
# and adding it to another queue
def my_callable(from_queue, to_queue):
    while True:
        try:
            tmp = from_queue.get(0)
            to_queue.put(tmp)
            print to_queue
        except Empty:
            break

# Create a master queue and fill it with numbers
main_queue = multiprocessing.Queue()
for i in xrange(100):
    main_queue.put(i)

all_queues = []
processes = []
# Create processes
for i in xrange(5):
    # Each process gets a queue that it will put numbers into
    queue = multiprocessing.Queue()
    # Keep up with the queue we are creating so we can get it later
    all_queues.append(queue)
    # Pass in our master queue and the queue we are transferring data to
    process = multiprocessing.Process(target=my_callable,
                                      args=(main_queue, queue))
    # Keep up with the processes
    processes.append(process)

for thread in processes:
    thread.start()

for thread in processes:
    thread.join()

当目标函数打印正在使用的队列时,您会注意到几乎只使用了一个队列。

如果你接着输出并打印出来,你会发现大多数数字最终都在一个队列中。

def queue_get_all(q):
   items = []
   maxItemsToRetreive = 100
   for numOfItemsRetrieved in range(0, maxItemsToRetreive):
       try:
           if numOfItemsRetrieved == maxItemsToRetreive:
               break
           items.append(q.get_nowait())
       except Empty, e:
           break
   return items

for tmp in all_queues:
    print queue_get_all(tmp)

造成这种情况的原因是什么?我的代码中是否有一些我应该做的事情会使这些过程正在进行的工作变得均匀?

输出

[0, 2, 3, 4, 5, 6, 7, 8]
[1, 9, 10]
[11, 14, 15, 16]
[12, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
[13]

1 个答案:

答案 0 :(得分:2)

我认为你有两个问题:

def my_callable(from_queue, to_queue):
    while True:
        try:
            tmp = from_queue.get(0)
            to_queue.put(tmp)
            print to_queue
        except Empty:
            break

来自get的文档:

  

从队列中删除并返回一个项目。如果可选的args块为True(默认值)且timeout为None(默认值),则在必要时阻止,直到某个项可用为止。如果timeout是一个正数,它会阻止最多超时秒,如果在该时间内没有可用的项,则会引发Queue.Empty异常。否则(块为False),如果一个项立即可用,则返回一个项,否则引发Queue.Empty异常(在这种情况下忽略超时)。

由于您将0作为第一个参数传递,因此它等同于get(False)。这使得它非阻塞,这意味着如果它无法立即获取值,它将引发一个Empty异常,这将结束您的工作进程。由于您的所有“工作”功能都是相同的,并且尝试同时从主队列中拉出来,因此有些人可能无法立即获得值并且会死亡。

.get()一个小超时应该可以解决这个问题。

第二个问题是你的'工作'功能基本上没有时间完成。使用sleep(.2)暂停一下,以模拟一些非繁琐的工作,它将分配给工人:

def my_callable(from_queue, to_queue):
    while True:
        try:
            tmp = from_queue.get(True, .1)
            sleep(0.2)
            to_queue.put(tmp)
        except Empty:
            break

修改

我忘了说,通常情况下,这种类型的问题最好不要依赖.get()的超时来表示队列的结束。如果您使用某种类型的“队列结束”标记对象,您可以获得更多控制权,并将其传递到队列中,该队列告诉工作人员是时候退出。通过这种方式,您可以将它们全部阻塞,等待新输入或退出“命令”。