Pergunta

Eu tenho um segmento que escreve os resultados em uma fila.

Em outro segmento (GUI), que periodicamente (no caso IDLE) verificar se existem resultados na fila, como este:

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

Esta é uma boa maneira de fazê-lo?

Editar:

Estou perguntando porque às vezes o thread em espera fica preso por alguns segundos sem tomar novo resultados.

O problema "preso" acabou por ser porque eu estava fazendo o processamento no manipulador de eventos ocioso, sem ter a certeza de que tais eventos são realmente gerado chamando wx.WakeUpIdle, como é recomendado.

Foi útil?

Solução

Eu ficaria muito surpreso se a chamada get_nowait() causou a pausa não retornando se a lista estava vazia.

Pode ser que você está postando um grande número de (? Talvez grandes) itens entre as verificações que significa o segmento de recepção tem uma grande quantidade de dados para puxar para fora do Queue? Você poderia tentar limitar o número de recuperar em um lote:

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

Isto limitaria o fio receber a puxar até 10 itens de uma vez.

Outras dicas

Se você está sempre puxando todos os itens disponíveis fora da fila, há qualquer verdadeiro ponto em usar uma fila, em vez de apenas uma lista com um bloqueio? ou seja:

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 você também está puxando-los individualmente, e fazendo uso do comportamento de bloqueio para filas vazias, então você deve usar fila, mas seu caso de uso parece muito mais simples, e pode ser melhor servido pela abordagem acima.

[Edit2] eu tinha perdido o fato de que você está polling da fila de um loop ocioso, e de sua atualização, vejo que o problema não está relacionado com a disputa, de modo que o aproximação abaixo não é realmente relevante para o seu problema. Deixei-o em caso alguém encontra uma variante bloqueio deste útil:

Para casos em que você quer bloquear até chegar pelo menos um resultado, você pode modificar o código acima para aguardar os dados para se tornar disponível através sendo sinalizado pelo segmento produtor. Por exemplo.

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

Eu acho que a maneira mais fácil de obter todos os itens fora da fila é o seguinte:

def get_all_queue_result(queue):

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

    return result_list

Eu vejo que você está usando get_nowait (), que de acordo com a documentação, "retorno [s] um item se um estiver disponível imediatamente, senão aumentar a exceção Empty"

Agora, acontecer de você sair do loop quando uma exceção vazio é lançada. Assim, se não houver nenhum resultado imediatamente disponível na fila, a sua função retorna uma lista de itens vazia.

Existe uma razão pela qual você não está usando o método get () em vez disso? Pode ser o caso que o get_nowait () falhar porque a fila é a manutenção de uma solicitação de venda () naquele mesmo momento.

Se você é feito por escrito para a fila, qsize deve fazer o truque sem a necessidade de verificar a fila para cada iteração.

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

O método mais simples é usar uma compreensão da lista:

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

O uso da função range é geralmente desaprovado, mas eu não ter encontrado um método mais simples ainda.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top