Resumo : neste tutorial, você aprenderá como usar uma fila segura para threads do Python para trocar dados com segurança entre vários threads.
Introdução à fila thread-safe do Python
O módulo integrado queue
permite a troca de dados com segurança entre vários threads . A Queue
classe no queue
módulo implementa toda a semântica de bloqueio necessária.
Criando uma nova fila
Para criar uma nova fila, importe a classe Queue do módulo queue:
from queue import Queue
Linguagem de código: Python ( python )
e use o Queue
construtor da seguinte maneira:
queue = Queue()
Linguagem de código: Python ( python )
Para criar uma fila com limite de tamanho, você pode usar o maxsize
parâmetro. Por exemplo, o seguinte cria uma fila que pode armazenar até 10 itens:
queue = Queue(maxsize=10)
Linguagem de código: Python ( python )
Adicionando um item à fila
Para adicionar um item à fila, você usa o put()
método como este:
queue.add(item)
Linguagem de código: Python ( python )
Quando a fila estiver cheia, você não poderá adicionar um item a ela. Além disso, a chamada ao put()
método será bloqueada até que a fila tenha espaço disponível.
Se você não deseja que o put()
método seja bloqueado se a fila estiver cheia, você pode definir o block
argumento como False
:
queue.put(item, block=False)
Linguagem de código: Python ( python )
Neste caso, o put()
método irá gerar a queue.Full
exceção se a fila estiver cheia:
try:
queue.put(item, block=False)
except queue.Full as e:
# handle exceptoin
Linguagem de código: Python ( python )
Para adicionar um item a uma fila de tamanho limitado e bloquear com tempo limite, você pode usar o timeout
parâmetro como este:
try:
queue.put(item, timeout=3)
except queue.Full as e:
# handle exceptoin
Linguagem de código: Python ( python )
Obtendo um item da fila
Para obter um item da fila, você pode usar o get()
método:
item = queue.get()
Linguagem de código: Python ( python )
O get()
método será bloqueado até que um item esteja disponível para recuperação da fila.
Para obter um item da fila sem bloqueio, você pode definir o parâmetro de bloqueio como False
:
try:
queue.get(block=False)
except queue.Empty:
# handle exception
Linguagem de código: Python ( python )
Para obter um item da fila e bloqueá-lo com limite de tempo, você pode usar o get()
método com tempo limite:
try:
item = queue.get(timeout=10)
except queue.Empty:
# ...
Linguagem de código: Python ( python )
Obtendo o tamanho da fila
O qsize()
método retorna o número de itens na fila:
size = queue.size()
Linguagem de código: Python ( python )
Além disso, o empty()
método retorna True
se a fila estiver vazia ou False caso contrário. Por outro lado, o full()
método retorna True se a fila estiver cheia ou False
não.
Marcando uma tarefa como concluída
Um item adicionado à fila representa uma unidade de trabalho ou uma tarefa.
Quando um thread chama o get()
método para obter o item da fila, pode ser necessário processá-lo antes que a tarefa seja considerada concluída.
Depois de concluído, o thread pode chamar o task_done()
método da fila para indicar que processou a tarefa completamente:
item = queue.get()
# process the item
# ...
# mark the item as completed
queue.task_done()
Linguagem de código: Python ( python )
Aguardando a conclusão de todas as tarefas na fila
Para aguardar a conclusão de todas as tarefas na fila, você pode chamar o join()
método no objeto da fila:
queue.join()
Linguagem de código: Python ( python )
Exemplo de fila segura para threads em Python
O exemplo a seguir ilustra como usar a fila thread-safe para trocar dados entre dois threads:
import time
from queue import Empty, Queue
from threading import Thread
def producer(queue):
for i in range(1, 6):
print(f'Inserting item {i} into the queue')
time.sleep(1)
queue.put(i)
def consumer(queue):
while True:
try:
item = queue.get()
except Empty:
continue
else:
print(f'Processing item {item}')
time.sleep(2)
queue.task_done()
def main():
queue = Queue()
# create a producer thread and start it
producer_thread = Thread(
target=producer,
args=(queue,)
)
producer_thread.start()
# create a consumer thread and start it
consumer_thread = Thread(
target=consumer,
args=(queue,),
daemon=True
)
consumer_thread.start()
# wait for all tasks to be added to the queue
producer_thread.join()
# wait for all tasks on the queue to be completed
queue.join()
if __name__ == '__main__':
main()
Linguagem de código: Python ( python )
Como funciona.
Primeiro, defina a producer()
função que adiciona números de 1 a 11 à fila. Atrasa um segundo em cada iteração:
def producer(queue):
for i in range(1, 6):
print(f'Inserting item {i} into the queue')
time.sleep(1)
queue.put(i)
Linguagem de código: Python ( python )
Segundo, defina a consumer()
função que obtém um item da fila e o processa. Atrasa dois segundos após o processamento de cada item da fila:
def consumer(queue):
while True:
try:
item = queue.get()
except Empty:
continue
else:
print(f'Processing item {item}')
time.sleep(2)
queue.task_done()
Linguagem de código: Python ( python )
A fila. task_done()
indica que a função processou o item na fila.
Terceiro, defina a main()
função que cria dois threads, um thread adiciona um número à fila a cada segundo enquanto outro thread processa um item na fila a cada dois segundos:
def main():
queue = Queue()
# create a producer thread and start it
producer_thread = Thread(
target=producer,
args=(queue,)
)
producer_thread.start()
# create a consumer thread and start it
consumer_thread = Thread(
target=consumer,
args=(queue,),
daemon=True
)
consumer_thread.start()
# wait for all tasks to be added to the queue
producer_thread.join()
# wait for all tasks on the queue to be completed
queue.join()
Linguagem de código: Python ( python )
Saída:
Inserting item 1 into the queue
Inserting item 2 into the queue
Processing item 1
Inserting item 3 into the queue
Processing item 2
Inserting item 4 into the queue
Inserting item 5 into the queue
Processing item 3
Processing item 4
Processing item 5
Linguagem de código: Python ( python )
A seguir estão as etapas da main()
função:
- Crie uma nova fila chamando o
Queue()
construtor - Crie um novo tópico chamado
producer_thread
e inicie-o imediatamente - Crie um thread daemon chamado
consumer_thread
e inicie-o imediatamente. - Aguarde até que todos os números sejam adicionados à fila usando o
join()
método do thread. - Aguarde que todas as tarefas da fila sejam concluídas chamando o
join()
método da fila.
O produtor adiciona um número à fila a cada segundo e o consumidor processa um número da fila a cada dois segundos. Ele também exibe os números da fila a cada segundo.
Resumo
- Use a
Queue
classe doqueue
módulo para trocar dados com segurança entre vários threads.