工作完成后,多线程生成新进程

时间:2014-06-14 15:22:27

标签: python multithreading

我想定义一个n个工作池,并让每个执行任务保存在rabbitmq队列中。当此任务完成(失败或成功)时,我希望工作人员从队列中执行另一个任务。

我可以在docs中看到如何产生一个工作池并让他们都等待他们的兄弟姐妹完成。我会喜欢不同的东西:我希望有一个n个任务的缓冲区,当一个工人完成时,它会向缓冲区添加另一个任务(所以在bugger中只有n个任务)。我在文档中搜索时遇到了困难。

对于上下文,我的非多线程代码是这样的:

while True:
    message = get_frame_from_queue() # get message from rabbit mq
    do_task(message.body) #body defines urls to download file
    acknowledge_complete(message) # tell rabbitmq the message is acknowledged

在这个阶段,我的“多线程”实现将如下所示:

@recieves('ask_for_a_job')
def get_a_task():
    # this function is executed when `ask_for_a_job` signal is fired
    message = get_frame_from_queue()
    do_task(message)

def do_tasks(task_info):
    try:
        # do stuff
    finally:
        # once the "worker" has finished start another.
        fire_fignal('ask_for_a_job')

# start the "workers"
for i in range(5):
    fire_fignal('ask_for_a_job')

我不想重新发明轮子。是否有更内置的方法来实现这一目标?

注意get_frame_from_queue不是线程安全的。

2 个答案:

答案 0 :(得分:2)

您应该能够让每个子进程/线程直接从队列中使用,然后在每个线程中,只需从队列中完全按照同步进行处理。

from threading import Thread

def do_task(msg):
   # Do stuff here

def consume():
    while True:
        message = get_frame_from_queue()
        do_task(message.body)
        acknowledge_complete(message)

if __name __ == "__main__":
    threads = []
    for i in range(5):
        t = Thread(target=consume)
        t.start()
        threads.append(t)

这样,您将始终同时处理来自队列的N条消息,而不需要在线程之间发出信号。

唯一的"陷阱"这是您正在使用的rabbitmq库的线程安全性。根据它的实现方式,每个线程可能需要一个单独的连接,或者每个线程可能需要一个通道连接等。

答案 1 :(得分:0)

一种解决方案是利用multiprocessing.Pool对象。使用外部循环从RabbitMQ获取N个项目。将项目提供给池,等待整个批处理完成。然后遍历批处理,确认每条消息。最后继续外循环。

import multiprocessing

def worker(word):
    return bool(word=='whiskey')

messages = ['syrup', 'whiskey', 'bitters']

BATCHSIZE = 2
pool = multiprocessing.Pool(BATCHSIZE)

while messages:
    # take first few messages, one per worker
    batch,messages = messages[:BATCHSIZE],messages[BATCHSIZE:]

    print 'BATCH:',
    for res in pool.imap_unordered(worker, batch):
        print res,
    print

    # TODO: acknowledge msgs in 'batch'

输出

BATCH: False True
BATCH: False