“select” on multiple Python multiprocessing Queues?

前端 未结 8 1494
情书的邮戳
情书的邮戳 2020-12-24 01:55

What\'s the best way to wait (without spinning) until something is available in either one of two (multiprocessing) Queues, where both reside on the same system?

8条回答
  •  天命终不由人
    2020-12-24 02:34

    New version of above code...

    Not sure how well the select on a multiprocessing queue works on windows. As select on windows listens for sockets and not file handles, I suspect there could be problems.

    My answer is to make a thread to listen to each queue in a blocking fashion, and to put the results all into a single queue listened to by the main thread, essentially multiplexing the individual queues into a single one.

    My code for doing this is:

    """
    Allow multiple queues to be waited upon.
    
    An EndOfQueueMarker marks a queue as
        "all data sent on this queue".
    When this marker has been accessed on
    all input threads, this marker is returned
    by the multi_queue.
    
    """
    import queue
    import threading
    
    class EndOfQueueMarker:
        def __str___(self):
            return "End of data marker"
        pass
    
    class queue_reader(threading.Thread):
        def __init__(self,inq,sharedq):
            threading.Thread.__init__(self)
            self.inq = inq
            self.sharedq = sharedq
        def run(self):
            q_run = True
            while q_run:
                data = self.inq.get()
                result = (self.inq,data)
                self.sharedq.put(result)
                if data is EndOfQueueMarker:
                    q_run = False
    
    class multi_queue(queue.Queue):
        def __init__(self,list_of_queues):
            queue.Queue.__init__(self)
            self.qList = list_of_queues
            self.qrList = []
            for q in list_of_queues:
                qr = queue_reader(q,self)
                qr.start()
                self.qrList.append(qr)
        def get(self,blocking=True,timeout=None):
            res = []
            while len(res)==0:
                if len(self.qList)==0:
                    res = (self,EndOfQueueMarker)
                else:
                    res = queue.Queue.get(self,blocking,timeout)
                    if res[1] is EndOfQueueMarker:
                        self.qList.remove(res[0])
                        res = []
            return res
    
        def join(self):
            for qr in self.qrList:
                qr.join()
    
    def select(list_of_queues):
        outq = queue.Queue()
        for q in list_of_queues:
            qr = queue_reader(q,outq)
            qr.start()
        return outq.get()
    

    The follow code is my test routine to show how it works:

    import multiq
    import queue
    
    q1 = queue.Queue()
    q2 = queue.Queue()
    
    q3 = multiq.multi_queue([q1,q2])
    
    q1.put(1)
    q2.put(2)
    q1.put(3)
    q1.put(4)
    q1.put(multiq.EndOfQueueMarker)
    q2.put(multiq.EndOfQueueMarker)
    res=0
    have_data = True
    while have_data:
        res = q3.get()[1]
        print ("returning result =",res)
        have_data = not(res==multiq.EndOfQueueMarker)
    

提交回复
热议问题