Get all items from thread Queue

后端 未结 6 1655
别那么骄傲
别那么骄傲 2021-02-13 05:14

I have one thread that writes results into a Queue.

In another thread (GUI), I periodically (in the IDLE event) check if there are results in the queue, like this:

相关标签:
6条回答
  • 2021-02-13 05:24

    If you're always pulling all available items off the queue, is there any real point in using a queue, rather than just a list with a lock? ie:

    from __future__ import with_statement
    import threading
    
    class ItemStore(object):
        def __init__(self):
            self.lock = threading.Lock()
            self.items = []
    
        def add(self, item):
            with self.lock:
                self.items.append(item)
    
        def getAll(self):
            with self.lock:
                items, self.items = self.items, []
            return items
    

    If you're also pulling them individually, and making use of the blocking behaviour for empty queues, then you should use Queue, but your use case looks much simpler, and might be better served by the above approach.

    [Edit2] I'd missed the fact that you're polling the queue from an idle loop, and from your update, I see that the problem isn't related to contention, so the below approach isn't really relevant to your problem. I've left it in in case anyone finds a blocking variant of this useful:

    For cases where you do want to block until you get at least one result, you can modify the above code to wait for data to become available through being signalled by the producer thread. Eg.

    class ItemStore(object):
        def __init__(self):
            self.cond = threading.Condition()
            self.items = []
    
        def add(self, item):
            with self.cond:
                self.items.append(item)
                self.cond.notify() # Wake 1 thread waiting on cond (if any)
    
        def getAll(self, blocking=False):
            with self.cond:
                # If blocking is true, always return at least 1 item
                while blocking and len(self.items) == 0:
                    self.cond.wait()
                items, self.items = self.items, []
            return items
    
    0 讨论(0)
  • 2021-02-13 05:35

    I'd be very surprised if the get_nowait() call caused the pause by not returning if the list was empty.

    Could it be that you're posting a large number of (maybe big?) items between checks which means the receiving thread has a large amount of data to pull out of the Queue? You could try limiting the number you retrieve in one batch:

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

    This would limit the receiving thread to pulling up to 10 items at a time.

    0 讨论(0)
  • 2021-02-13 05:35

    If you're done writing to the queue, qsize should do the trick without needing to check the queue for each iteration.

    responseList = []
    for items in range(0, q.qsize()):
        responseList.append(q.get_nowait())
    
    0 讨论(0)
  • 2021-02-13 05:42

    The simplest method is using a list comprehension:

    items = [q.get() for _ in range(q.qsize())]
    

    Use of the range function is generally frowned upon, but I haven't found a simpler method yet.

    0 讨论(0)
  • 2021-02-13 05:42

    I see you are using get_nowait() which according to the documentation, "return[s] an item if one is immediately available, else raise the Empty exception"

    Now, you happen to break out of the loop when an Empty exception is thrown. Thus, if there is no result immediately available in the queue, your function returns an empty items list.

    Is there a reason why you are not using the get() method instead? It may be the case that the get_nowait() fails because the queue is servicing a put() request at that same moment.

    0 讨论(0)
  • 2021-02-13 05:44

    I think the easiest way of getting all items out of the queue is the following:

    def get_all_queue_result(queue):
    
        result_list = []
        while not queue.empty():
            result_list.append(queue.get())
    
        return result_list
    
    0 讨论(0)
提交回复
热议问题