简体   繁体   English

在进程之间共享队列

[英]Share queue between processes

I am pretty new to multiprocessing in python and trying to achieve something which should be a rather common thing to do.我对 python 中的多处理非常陌生,并试图实现一些应该是相当常见的事情。 But I cannot find an easy way when searching the web.但是我在搜索网络时找不到简单的方法。

I want to put data in a queue and then make this queue available to different consumer functions.我想将数据放入队列中,然后使该队列可用于不同的消费者功能。 Of course when getting an element from the queue, all consumer functions should get the same element.当然,从队列中获取元素时,所有消费者函数都应该获取相同的元素。 The following example should make clear what I want to achieve:以下示例应该清楚我想要实现的目标:

from multiprocessing import Process, Queue

def producer(q):

    for i in range(10):
        
        q.put(i)
    
    q.put(None)

def consumer1(q):
    while True:
        data = q.get()
        
        if data is None:   
            break
   
        print(data)

def consumer2(q):

    while True:
        data = q.get()
        
        if data is None:   
            break
   
        print(data)

def main():
    q = Queue()
    p1 = Process(target=producer, args=(q,))
    p2 = Process(target=consumer1, args=(q,))
    p3 = Process(target=consumer2, args=(q,))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()


if __name__ == '__main__':
    main()

Since the script is not terminating and I only get the print output of one function I guess this is not the way to do it.由于脚本没有终止,我只得到一个函数的打印输出,我猜这不是这样做的方法。 I think sharing a queue implies some things to consider?我认为共享队列意味着需要考虑一些事情? It works fine when using only one consumer function.仅使用一个消费者功能时它工作正常。 Appreciate the help!感谢帮助!

Your question exemplifies the misunderstanding你的问题是误解的例证

"all consumer functions should get the same element" “所有消费者功能都应该获得相同的元素”

That's just not how queues work.这不是队列的工作方式。 Queues are automatically managed (there's quite a lot under the hood) such if one item is put in, only one item can be taken out.队列是自动管理的(引擎盖下有很多),如果放入一件物品,只能取出一件物品。 That item is not duplicated to all consumers.该项目不会复制给所有消费者。 It seems like you actually need two separate queues to guarantee that each consumer gets each input without competing against the other consumer:看起来您实际上需要两个单独的队列来保证每个消费者获得每个输入而不与另一个消费者竞争:

from multiprocessing import Process, Queue

def producer(q1, q2):

    for i in range(10):
        
        q1.put(i)
        q2.put(i)
    
    q1.put(None)
    q2.put(None)

def consumer1(q):
    while True:
        data = q.get()
        
        if data is None:   
            break
   
        print(data)

def consumer2(q):

    while True:
        data = q.get()
        
        if data is None:   
            break
   
        print(data)

def main():
    q1 = Queue()
    q2 = Queue()
    p1 = Process(target=producer,  args=(q1, q2))
    p2 = Process(target=consumer1, args=(q1,))
    p3 = Process(target=consumer2, args=(q2,))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()


if __name__ == '__main__':
    main()

If the values you are storing can be represented by one of the fundamental data types defined in the ctypes module , then the following could work.如果您存储的值可以由ctypes模块中定义的一种基本数据类型表示,那么以下方法可以工作。 Here we are implementing a "queue" that can hold int values or None:在这里,我们正在实现一个可以保存 int 值或 None 的“队列”:

from multiprocessing import Process, Condition
import ctypes
from multiprocessing.sharedctypes import RawArray, RawValue
from threading import local
import time

my_local = local()
my_local.current = 0

class StructuredInt(ctypes.Structure):
    """
    This class is necessary because we want to be able to store in the RawArray
    either an int or None, which requires using ctypes.c_void_p as the array type.
    But, infortunately, ctypes.c_void_p(0) is interpreted as None.
    So we need a way to represent 0. Field value 'value' is the
    actual int value being stored and we use an arbitrarty 'ptr'
    field value that will not be interpreted as None.

    To store a None value, we set 'ptr' to ctypes.c_void_p(None) and field
    'value' is irrelevant.

    To store an integer. we set 'ptr' to ctypes.c_void_p(1) and field
    'value' has the actual value.
    """
    _fields_ = [('ptr', ctypes.c_void_p), ('value', ctypes.c_int)]

class MultiIntQueue:
    """
    An integer queue that can be processed by multiple threads where each thread
    can retrieve all the values added to the queue.

    :param maxsize: The maximum queue capacity (defaults to 20 if specified as None)
    :type maxsize: int
    """

    def __init__(self, maxsize=None):
        if maxsize is None:
            maxsize = 20
        self.maxsize = maxsize
        self.q = RawArray(StructuredInt, maxsize)
        self.condition = Condition()
        self.size = RawValue(ctypes.c_int, 0)

    def get(self):
        with self.condition:
            while my_local.current >= self.size.value:
                self.condition.wait()
        i = self.q[my_local.current]
        my_local.current += 1
        return None if i.ptr is None else i.value

    def put(self, i):
        assert 0 <= self.size.value < self.maxsize
        with self.condition:
            self.q[self.size.value] = (ctypes.c_void_p(None), 0) if i is None else (ctypes.c_void_p(1), i)
            self.size.value += 1
            self.condition.notify_all()


def producer(q):

    for i in range(10):
        q.put(i)
        time.sleep(.3) # simulate processing

    q.put(None)

def consumer1(q):
    while True:
        data = q.get()

        if data is None:
            break
        time.sleep(.1) # simulate processing

        print('Consumer 1:', data)

def consumer2(q):

    while True:
        data = q.get()

        if data is None:
            break
        time.sleep(.1) # simulate processing

        print('Consumer 2:', data)

def main():
    q = MultiIntQueue()
    p1 = Process(target=producer,  args=(q,))
    p2 = Process(target=consumer1, args=(q,))
    p3 = Process(target=consumer2, args=(q,))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()


if __name__ == '__main__':
    main()

Prints:印刷:

Consumer 1: 0
Consumer 2: 0
Consumer 2: 1
Consumer 1: 1
Consumer 2: 2
Consumer 1: 2
Consumer 2: 3
Consumer 1: 3
Consumer 2: 4
Consumer 1: 4
Consumer 1: 5
Consumer 2: 5
Consumer 1: 6
Consumer 2: 6
Consumer 1: 7
Consumer 2: 7
Consumer 2: 8
Consumer 1: 8
Consumer 1: 9
Consumer 2: 9

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM