单一生产者多个消费者

时间:2015-02-05 16:38:18

标签: python multithreading queue

我希望在执行多线程编程时,在Python中拥有一个单一的生产者,多个消费者体系结构。我希望有这样的操作:

  1. 生产者生成数据
  2. 消费者1 .. N(N预先确定)等待数据到达(阻止),然后以不同方式处理SAME数据。
  3. 所以我需要所有消费者从制作人那里获得相同的数据。

    当我使用Queue执行此操作时,我意识到除了第一个消费者之外的所有消费者都会因为我的实施而受到匮乏。

    一种可能的解决方案是为每个消费者线程建立一个唯一的队列,其中生产者在多个队列中推送相同的数据。有更好的方法吗?

    from threading import Thread
    import time
    import random
    from Queue import Queue
    
    my_queue = Queue(0)
    
    def Producer():
        global my_queue
        my_list = []
        for each in range (50):
            my_list.append(each)
        my_queue.put(my_list)
    
    def Consumer1():
        print "Consumer1"
        global my_queue
        print my_queue.get()
        my_queue.task_done()
    
    def Consumer2():
        print "Consumer2"
        global my_queue
        print my_queue.get()
        my_queue.task_done()
    
    
    P = Thread(name = "Producer", target = Producer)
    
    C1 = Thread(name = "Consumer1", target = Consumer1)
    
    C2 = Thread(name = "Consumer2", target = Consumer2)
    
    
    P.start()
    
    C1.start()
    
    C2.start()
    

    在上面的例子中,当C1消耗P1产生的数据时,C2无限期地被阻塞。我想要的是C1和C2都能够访问由P1产生的SAME数据。

    感谢任何代码/指针!

3 个答案:

答案 0 :(得分:2)

您的制作人只创建一项工作:

my_queue.put(my_list)

例如,将my_list放两次,两位消费者都可以工作:

def Producer():
    global my_queue
    my_list = []
    for each in range (50):
        my_list.append(each)
    my_queue.put(my_list)
    my_queue.put(my_list)

因此,通过这种方式,您可以将两个作业放入具有相同列表的队列中。

但是我必须警告你:在没有线程同步的情况下修改不同线程中的相同数据通常是个坏主意。

无论如何,使用一个队列的方法对你来说不起作用,因为一个队列应该用具有相同算法的线程处理。

所以,我建议你为每个消费者提供独特的队列,因为其他解决方案并不是那么简单。

答案 1 :(得分:1)

那么每个线程的队列呢?

作为启动每个消费者的一部分,您还将创建另一个队列,并将其添加到"所有线程队列"的列表中。然后启动生产者,将所有队列的列表传递给他,然后他可以将数据推送到所有队列中。

答案 2 :(得分:1)

一个单一生产者和五个消费者的例子,经过验证。

from multiprocessing import Process, JoinableQueue
import time
import os

q = JoinableQueue()

def producer():
    for item in range(30):
        time.sleep(2)
        q.put(item)
    pid = os.getpid()
    print(f'producer {pid} done')


def worker():
    while True:
        item = q.get()
        pid = os.getpid()
        print(f'pid {pid} Working on {item}')
        print(f'pid {pid} Finished {item}')
        q.task_done()

for i in range(5):
    p = Process(target=worker, daemon=True).start()

producers = []
# it is easy to extend it to multi producers.
for i in range(1):
    p = Process(target=producer)
    producers.append(p)
    p.start()

# make sure producers done
for p in producers:
    p.join()

# block until all workers are done
q.join()
print('All work completed')

说明:

  1. 在此示例中为一个生产者和五个消费者。
  2. JoinableQueue 用于确保存储在队列中的所有元素都将被处理。 'task_done' 是让工作人员通知元素已完成。 'q.join()' 将等待所有标记为完成的元素。
  3. 使用 #2,无需为每个工人加入等待。
  4. 但是加入等待生产者将元素存储到队列中很重要。否则,程序立即退出。