Domanda

Ho un thread che scrive i risultati in una coda.

In un altro thread (GUI), controllo periodicamente (nell'evento IDLE) se ci sono risultati nella coda, in questo modo:

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

È un buon modo per farlo?

Modifica

  

Lo chiedo perché a volte il   il thread in attesa si blocca per alcuni   secondi senza toglierne di nuovi   risultati.

Il "quot" bloccato " il problema si è verificato perché stavo eseguendo l'elaborazione nel gestore eventi inattivo, senza assicurarmi che tali eventi siano effettivamente generati chiamando wx.WakeUpIdle , come raccomandato.

È stato utile?

Soluzione

Sarei molto sorpreso se la chiamata get_nowait () causasse la pausa non tornando se l'elenco era vuoto.

Potrebbe essere che stai inserendo un gran numero di (forse grandi?) elementi tra i controlli, il che significa che il thread di ricezione ha una grande quantità di dati da estrarre dalla Queue ? Potresti provare a limitare il numero che recuperi in un batch:

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

Ciò limiterebbe il thread di ricezione a estrarre fino a 10 elementi alla volta.

Altri suggerimenti

Se stai sempre tirando fuori dalla coda tutti gli elementi disponibili, c'è davvero un punto nell'usare una coda, piuttosto che un semplice elenco con un lucchetto? vale a dire:

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

Se li stai anche estraendo singolarmente e stai usando il comportamento di blocco per le code vuote, allora dovresti usare Queue, ma il tuo caso d'uso sembra molto più semplice e potrebbe essere meglio servito dall'approccio sopra.

[Modifica2] Ho perso il fatto che stai eseguendo il polling della coda da un ciclo inattivo e dal tuo aggiornamento, vedo che il problema non è correlato alla contesa, quindi il l'approccio di seguito non è pertinente al tuo problema L'ho lasciato nel caso in cui qualcuno trovasse una variante bloccante di questo utile:

Per i casi in cui si desidera bloccare fino a quando non si ottiene almeno un risultato, è possibile modificare il codice sopra per attendere che i dati diventino disponibili tramite la segnalazione del thread del produttore. 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

Penso che il modo più semplice per estrarre tutti gli elementi dalla coda sia il seguente:

def get_all_queue_result(queue):

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

    return result_list

Vedo che stai usando get_nowait () che secondo la documentazione, " restituisce [s] un articolo se uno è immediatamente disponibile, altrimenti solleva l'eccezione Vuota "

Ora, ti capita di uscire dal ciclo quando viene generata un'eccezione Vuota. Pertanto, se non ci sono risultati immediatamente disponibili nella coda, la funzione restituisce un elenco di elementi vuoto.

C'è un motivo per cui non si utilizza invece il metodo get ()? È possibile che get_nowait () non riesca perché la coda sta servendo una richiesta put () nello stesso momento.

Se hai finito di scrivere sulla coda, qsize dovrebbe fare il trucco senza dover controllare la coda per ogni iterazione.

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

Il metodo più semplice sta usando una comprensione dell'elenco:

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

L'uso della funzione range è generalmente disapprovato, ma non ho ancora trovato un metodo più semplice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top