2008-10-01 5 views
12

Ich habe einen Thread, der Ergebnisse in eine Warteschlange schreibt.Erhalten Sie alle Elemente aus dem Thread Queue

In einem anderen Thread (GUI), ich in regelmäßigen Abständen (im IDLE-Ereignis) überprüfen, ob es Ergebnisse in der Warteschlange befinden, wie folgt aus:

def queue_get_all(q): 
    items = [] 
    while 1: 
     try: 
      items.append(q.get_nowait()) 
     except Empty, e: 
      break 
    return items 

Ist dies ein guter Weg, es zu tun?

Edit:

Ich frage, weil manchmal die wartet Thread für ein paar Sekunden stecken bleibt, ohne dass neue Ergebnisse herausnehmen.

Das „stecken“ Problem stellte sich heraus zu sein, weil ich die Verarbeitung im Leerlauf Ereignishandler tat, ohne darauf achten, dass solche Ereignisse durch tatsächlich erzeugt werden wx.WakeUpIdle Aufruf, wie empfohlen.

Antwort

7

Ich wäre sehr überrascht, wenn der get_nowait() Anruf die Pause von nicht zurückkehren, wenn die Liste leer verursacht.

Könnte es sein, dass Sie eine große Anzahl von (vielleicht großen?) Artikel zwischen den Prüfungen buchen, was bedeutet, dass der Empfänger-Thread eine große Menge an Daten aus dem Queue herausziehen? Sie könnten versuchen, die Nummer, die Sie in einer Charge abrufen zu beschränken:

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

Dies würde zu einem Zeitpunkt, zu ziehen bis zu 10 Stück des Aufnahmegewinde begrenzen.

+0

Es könnte lange Wartezeiten verursachen, wenn er es in einer Weile 1: busyloop anruft. Wenn dies der Fall ist, würde der Verbraucher nicht nur die Zeitfenster des Produzenten reduzieren, sondern würde auch viel Zeit darauf verwenden, die Warteschlangensperre zu halten, was möglicherweise den Produzenten in die Flucht schlagen würde. (Dies ist wahrscheinlicher, wenn er mehrere Consumer-Threads hat.) – Brian

+0

Guter Punkt Brian. Ich hatte den Eindruck, dass Eliben das nicht alles nannte, aber ich könnte mich irren - Eliben? –

+0

Hoppla, da hast du recht - ich habe den Teil vermisst, als ich ihn in einem Leerlauf aufgerufen habe. Das wäre nicht genug, um solche Probleme zu verursachen. – Brian

1

Ich sehe Sie verwenden get_nowait(), die entsprechend der Dokumentation „return [s] ein Element, wenn man sofort verfügbar ist, sonst heben die Leere Ausnahme“

Nun, passieren Sie aus der brechen Schleife, wenn eine leere Ausnahme ausgelöst wird. Wenn also in der Warteschlange kein Ergebnis verfügbar ist, gibt Ihre Funktion eine Liste leerer Elemente zurück.

Gibt es einen Grund, warum Sie nicht stattdessen die Methode get() verwenden? Es kann der Fall sein, dass get_nowait() fehlschlägt, weil die Warteschlange im gleichen Moment eine put() - Anfrage bearbeitet.

+1

Ich benutze nicht get(), weil ich nicht die GUI blockieren möchte. Es ist in Ordnung, wenn der Anruf denkt, es gibt nichts im Q, gerade wenn ein neues Element eingefügt wird, weil ich es regelmäßig nenne –

12

Wenn Sie immer alle verfügbaren Elemente aus der Warteschlange entfernen, gibt es einen wirklichen Vorteil bei der Verwendung einer Warteschlange statt nur einer Liste mit einer Sperre? dh:

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 

Wenn Sie auch einzeln, und die Nutzung des Sperrverhalten für leere Warteschlangen ziehen, dann sollten Sie Queue verwenden, aber Ihren Anwendungsfall sieht viel einfacher, und vielleicht besser durch die serviert werden über dem Ansatz.

[Edit2] Ich habe die Tatsache verpasst, dass Sie die Warteschlange von einer Leerlaufschleife abfragen, und von Ihrem Update sehe ich, dass das Problem nicht mit Konflikten verbunden ist, so ist der folgende Ansatz nicht t wirklich relevant für Ihr Problem. Ich habe es gelassen, falls jemand eine blockierende Variante dieses nützlichen findet:

Für Fälle, in denen Sie blockieren möchten, bis Sie mindestens ein Ergebnis erhalten, können Sie den obigen Code ändern, um auf Daten zu warten indem es vom Produzenten-Thread signalisiert wird. Z.B.

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 
5

Ich denke, der einfachste Weg, um alle Elemente des Erhaltens aus der Warteschlange die folgende ist:

def get_all_queue_result(queue): 

    result_list = [] 
    while not queue.empty(): 
     result_list.append(queue.get()) 

    return result_list 
+1

Dies könnte Ihnen immer noch eine Ausnahme geben. Aus der Dokumentation: Wenn empty() True zurückgibt, garantiert es nicht, dass ein nachfolgender Aufruf von put() nicht blockiert wird. Wenn empty() False zurückgibt, garantiert dies nicht, dass ein nachfolgender Aufruf von get() nicht blockiert wird. https://docs.python.org/2/library/queue.html – fantabolous

0

Wenn Sie in die Warteschlange fertig schreiben, WGröße sollte es tun, ohne um die Warteschlange zu überprüfen jede Iteration.

responseList = [] 
for items in range(0, q.qsize()): 
    responseList.append(q.get_nowait()) 
+0

'qsize' ist ähnlich wie 'leer', da es nicht garantiert ist. Aus der Dokumentation: Geben Sie die ungefähre Größe der Warteschlange an. Beachten Sie, dass qsize()> 0 nicht garantiert, dass ein nachfolgendes get() nicht blockiert, noch wird qsize() fantabolous

Verwandte Themen