Python para Desenvolvedores

2ª edição, revisada e ampliada

Capítulo 26: Threads


Uma thread é uma linha de execução que compartilha sua área de memória com outras linhas, ao contrário do processo tradicional, que possui apenas uma linha com área de memória própria.

Exemplo de threads num processo

O uso de threads oferece algumas vantagens em relação aos processos convencionais:

  • Consomem menos recursos de máquina.
  • Podem ser criadas e destruídas mais rapidamente.
  • Podem ser chaveadas mais rapidamente.
  • Podem se comunicar com outras threads de forma mais fácil.

É comum utilizar threads para:

  • Processamento paralelo, em casos como atender várias conexões em processos servidores.
  • Executar operações de I/O assíncronas, por exemplo: enquanto o usuário continua interagindo com a interface enquanto a aplicação envia um documento para a impressora.
  • Operações de I/O em paralelo.

Em Python, o módulo da biblioteca padrão threading provê classes de alto nível de abstração e usa o módulo thread, que implementa as rotinas de baixo nível e geralmente não é usado diretamente.

Exemplo com o módulo threading:

In [1]:
"""
Exemplo de uso de threads
"""

import os
import time
import threading


class Monitor(threading.Thread):
    """
    Classe de monitoramento usando threads
    """
    def __init__(self, ip):
        """
        Construtor da thread
        """
        # Atributos para a thread
        self.ip = ip
        self.status = None

        # Inicializador da classe Thread
        threading.Thread.__init__(self)

    def run(self):
        """
        Código que será executado pela thread
        """
        # Execute o ping
        ping = os.popen('ping -n 1 %s' % self.ip).read()

        if 'Esgotado' in ping:
            self.status = False
        else:
            self.status = True


if __name__ == '__main__':

    # Crie uma lista com um objeto de thread para cada IP
    monitores = []
    for i in range(1, 11):

        ip = '10.10.10.%d' % i
        monitores.append(Monitor(ip))

    # Execute as Threads
    for monitor in monitores:
        monitor.start()

    # A thread principal continua enquanto
    # as outras threads executam o ping
    # para os endereços da lista

    # Verifique a cada segundo
    # se as threads acabaram
    ping = True

    while ping:
        ping = False

        for monitor in monitores:
            if monitor.status == None:
                ping = True
                break
            
        time.sleep(1)

    # Imprima os resultados no final
    for monitor in monitores:

        if monitor.status:
            print '%s no ar' % monitor.ip
        else:
            print '%s fora do ar' % monitor.ip
10.10.10.1 no ar
10.10.10.2 no ar
10.10.10.3 no ar
10.10.10.4 no ar
10.10.10.5 no ar
10.10.10.6 no ar
10.10.10.7 no ar
10.10.10.8 no ar
10.10.10.9 no ar
10.10.10.10 no ar

É importante observar que, quando o processo morre, todas as suas threads terminam.

Na versão 2.6, está disponível também o módulo multiprocessing, que implementa classes para a criação de processos e a comunicação entre eles.

In [1]:
 
Out[1]: