Fila segura para threads do Python – 03

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 queuepermite a troca de dados com segurança entre vários threads . A Queueclasse no queuemó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 QueueLinguagem de código:  Python  ( python )

e use o Queueconstrutor da seguinte maneira:

queue = Queue()Linguagem de código:  Python  ( python )

Para criar uma fila com limite de tamanho, você pode usar o maxsizeparâ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 blockargumento como False:

queue.put(item, block=False)Linguagem de código:  Python  ( python )

Neste caso, o put()método irá gerar a queue.Fullexceção se a fila estiver cheia:

try:
   queue.put(item, block=False)
except queue.Full as e:
   # handle exceptoinLinguagem de código:  Python  ( python )

Para adicionar um item a uma fila de tamanho limitado e bloquear com tempo limite, você pode usar o timeoutparâmetro como este:

try:
   queue.put(item, timeout=3)
except queue.Full as e:
   # handle exceptoinLinguagem 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 exceptionLinguagem 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 Truese a fila estiver vazia ou False caso contrário. Por outro lado, o full()método retorna True se a fila estiver cheia ou Falsenã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 5Linguagem de código:  Python  ( python )

A seguir estão as etapas da main()função:

  1. Crie uma nova fila chamando o Queue()construtor
  2. Crie um novo tópico chamado producer_threade inicie-o imediatamente
  3. Crie um thread daemon chamado consumer_threade inicie-o imediatamente.
  4. Aguarde até que todos os números sejam adicionados à fila usando o join()método do thread.
  5. 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 Queueclasse do queuemódulo para trocar dados com segurança entre vários threads.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *