Multithreading em Python com Exemplo:Aprenda GIL em Python
A linguagem de programação python permite que você use multiprocessamento ou multithreading. Neste tutorial, você aprenderá como escrever aplicativos multithread em Python.
O que é um Tópico?
Uma thread é uma unidade de execução em programação concorrente. Multithreading é uma técnica que permite que uma CPU execute várias tarefas de um processo ao mesmo tempo. Esses threads podem ser executados individualmente enquanto compartilham seus recursos de processo.
O que é um processo?
Um processo é basicamente o programa em execução. Quando você inicia um aplicativo em seu computador (como um navegador ou editor de texto), o sistema operacional cria um processo .
O que é multithreading em Python?
Multithreading em Python A programação é uma técnica bem conhecida na qual vários threads em um processo compartilham seu espaço de dados com o thread principal, o que torna o compartilhamento de informações e a comunicação dentro dos threads fácil e eficiente. Threads são mais leves que processos. Multi threads podem ser executados individualmente enquanto compartilham seus recursos de processo. O objetivo do multithreading é executar várias tarefas e células de função ao mesmo tempo.
Neste tutorial, você aprenderá,
- O que é um Tópico?
- O que é um processo?
- O que é multithreading?
- O que é multiprocessamento?
- Multithreading em Python x multiprocessamento
- Por que usar Multithreading?
- MultiThreading Python
- Os módulos Thread e Threading
- O módulo Thread
- O módulo de encadeamento
- Deadlocks e condições de corrida
- Sincronizando conversas
- O que é GIL?
- Por que o GIL era necessário?
O que é multiprocessamento?
O multiprocessamento permite executar vários processos não relacionados simultaneamente. Esses processos não compartilham seus recursos e se comunicam por meio do IPC.
Python Multithreading vs Multiprocessing
Para entender processos e threads, considere este cenário:Um arquivo .exe em seu computador é um programa. Quando você o abre, o sistema operacional o carrega na memória e a CPU o executa. A instância do programa que está sendo executada agora é chamada de processo.
Todo processo terá 2 componentes fundamentais:
- O Código
- Os dados
Agora, um processo pode conter uma ou mais subpartes chamadas threads. Isso depende da arquitetura do sistema operacional. Você pode pensar em uma thread como uma seção do processo que pode ser executada separadamente pelo sistema operacional.
Em outras palavras, é um fluxo de instruções que pode ser executado independentemente pelo sistema operacional. Threads dentro de um único processo compartilham os dados desse processo e são projetados para trabalhar juntos para facilitar o paralelismo.
Por que usar Multithreading?
O multithreading permite dividir um aplicativo em várias subtarefas e executar essas tarefas simultaneamente. Se você usar o multithreading corretamente, a velocidade, o desempenho e a renderização de seu aplicativo poderão ser aprimorados.
Python MultiThreading
Python suporta construções tanto para multiprocessamento quanto para multithreading. Neste tutorial, você se concentrará principalmente na implementação de multithreaded aplicativos com python. Existem dois módulos principais que podem ser usados para lidar com threads em Python:
- O tópico módulo e
- O encadeamento módulo
No entanto, em python, também existe algo chamado de bloqueio de intérprete global (GIL). Ele não permite muito ganho de desempenho e pode até reduzir o desempenho de alguns aplicativos multithread. Você aprenderá tudo sobre isso nas próximas seções deste tutorial.
Os módulos Thread e Threading
Os dois módulos que você aprenderá neste tutorial são o módulo de thread e o módulo de encadeamento .
No entanto, o módulo de thread foi preterido há muito tempo. A partir do Python 3, ele foi designado como obsoleto e só pode ser acessado como __thread para compatibilidade com versões anteriores.
Você deve usar o encadeamento de nível superior módulo para aplicativos que você pretende implantar. O módulo de tópicos foi abordado aqui apenas para fins educacionais.
O módulo Thread
A sintaxe para criar um novo thread usando este módulo é a seguinte:
thread.start_new_thread(function_name, arguments)
Tudo bem, agora você cobriu a teoria básica para começar a codificar. Então, abra seu IDLE ou um bloco de notas e digite o seguinte:
import time import _thread def thread_test(name, wait): i = 0 while i <= 3: time.sleep(wait) print("Running %s\n" %name) i = i + 1 print("%s has finished execution" %name) if __name__ == "__main__": _thread.start_new_thread(thread_test, ("First Thread", 1)) _thread.start_new_thread(thread_test, ("Second Thread", 2)) _thread.start_new_thread(thread_test, ("Third Thread", 3))
Salve o arquivo e pressione F5 para executar o programa. Se tudo foi feito corretamente, esta é a saída que você deve ver:
Você aprenderá mais sobre as condições da corrida e como lidar com elas nas próximas seções
EXPLICAÇÃO DO CÓDIGO
- Essas instruções importam o módulo de tempo e encadeamento que são usados para lidar com a execução e o atraso dos encadeamentos do Python.
- Aqui, você definiu uma função chamada thread_test, que será chamado pelo start_new_thread método. A função executa um loop while por quatro iterações e imprime o nome da thread que a chamou. Quando a iteração estiver concluída, ele imprime uma mensagem informando que o encadeamento terminou a execução.
- Esta é a seção principal do seu programa. Aqui, você simplesmente chama o start_new_thread método com o thread_test função como um argumento. Isso criará uma nova thread para a função que você passar como argumento e começará a executá-la. Observe que você pode substituir isso (thread_ test) com qualquer outra função que você deseja executar como um encadeamento.
Módulo de Threading
Este módulo é a implementação de alto nível de threading em python e o padrão de fato para gerenciar aplicativos multithread. Ele fornece uma ampla gama de recursos quando comparado ao módulo de rosca.
Aqui está uma lista de algumas funções úteis definidas neste módulo:
Nome da função | Descrição |
---|---|
activeCount() | Retorna a contagem de Thread objetos que ainda estão vivos |
atualThread() | Retorna o objeto atual da classe Thread. |
enumerar() | Lista todos os objetos Thread ativos. |
isDaemon() | Retorna true se o thread for um daemon. |
isAlive() | Retorna verdadeiro se o encadeamento ainda estiver ativo. |
Métodos de classe de thread | |
iniciar() | Inicia a atividade de um thread. Ele deve ser chamado apenas uma vez para cada thread porque lançará um erro de tempo de execução se for chamado várias vezes. |
executar() | Este método denota a atividade de um thread e pode ser substituído por uma classe que estende a classe Thread. |
juntar() | Ele bloqueia a execução de outro código até que o encadeamento no qual o método join() foi chamado seja encerrado. |
História:A classe de tópicos
Antes de começar a codificar programas multithread usando o módulo threading, é crucial entender sobre a classe Thread. A classe thread é a classe primária que define o template e as operações de uma thread em python.
A maneira mais comum de criar um aplicativo python multithread é declarar uma classe que estende a classe Thread e substitui seu método run().
A classe Thread, em resumo, significa uma sequência de código que é executada em um thread separado de controle.
Portanto, ao escrever um aplicativo multithread, você fará o seguinte:
- defina uma classe que estende a classe Thread
- Substituir o __init__ construtor
- Substituir o run() método
Depois que um objeto de thread é criado, o start() pode ser usado para iniciar a execução desta atividade e o join() pode ser usado para bloquear todos os outros códigos até que a atividade atual termine.
Agora, vamos tentar usar o módulo de encadeamento para implementar seu exemplo anterior. Novamente, inicie seu IDLE e digite o seguinte:
import time import threading class threadtester (threading.Thread): def __init__(self, id, name, i): threading.Thread.__init__(self) self.id = id self.name = name self.i = i def run(self): thread_test(self.name, self.i, 5) print ("%s has finished execution " %self.name) def thread_test(name, wait, i): while i: time.sleep(wait) print ("Running %s \n" %name) i = i - 1 if __name__=="__main__": thread1 = threadtester(1, "First Thread", 1) thread2 = threadtester(2, "Second Thread", 2) thread3 = threadtester(3, "Third Thread", 3) thread1.start() thread2.start() thread3.start() thread1.join() thread2.join() thread3.join()
Esta será a saída quando você executar o código acima:
EXPLICAÇÃO DO CÓDIGO
- Esta parte é igual ao nosso exemplo anterior. Aqui, você importa o módulo de tempo e encadeamento que são usados para lidar com a execução e os atrasos dos encadeamentos do Python.
- Neste bit, você está criando uma classe chamada threadtester, que herda ou estende o Thread classe do módulo de rosqueamento. Esta é uma das maneiras mais comuns de criar threads em python. No entanto, você só deve substituir o construtor e o run() método em seu aplicativo. Como você pode ver no exemplo de código acima, o __init__ método (construtor) foi substituído. Da mesma forma, você também substituiu o run() método. Ele contém o código que você deseja executar dentro de um thread. Neste exemplo, você chamou a função thread_test().
- Este é o método thread_test() que recebe o valor de i como argumento, diminui-o em 1 em cada iteração e percorre o resto do código até que i se torne 0. Em cada iteração, imprime o nome da linha de execução actualmente em execução e dorme durante os segundos de espera (o que também é tomado como argumento ).
- thread1 =threadtester(1, “First Thread”, 1) Aqui, estamos criando uma thread e passando os três parâmetros que declaramos em __init__. O primeiro parâmetro é o id do encadeamento, o segundo parâmetro é o nome do encadeamento e o terceiro parâmetro é o contador, que determina quantas vezes o loop while deve ser executado.
- thread2.start() O método start é usado para iniciar a execução de uma thread. Internamente, a função start() chama o método run() de sua classe.
- thread3.join() O método join() bloqueia a execução de outro código e espera até que a thread em que foi chamado termine.
Como você já sabe, as threads que estão no mesmo processo têm acesso à memória e aos dados desse processo. Como resultado, se mais de um thread tentar alterar ou acessar os dados simultaneamente, poderão ocorrer erros.
Na próxima seção, você verá os diferentes tipos de complicações que podem aparecer quando as threads acessam os dados e a seção crítica sem verificar as transações de acesso existentes.
Deadlocks e condições de corrida
Antes de aprender sobre deadlocks e condições de corrida, será útil entender algumas definições básicas relacionadas à programação simultânea:
- Seção CríticaÉ um fragmento de código que acessa ou modifica variáveis compartilhadas e deve ser realizada como uma transação atômica.
- Mudança de contextoÉ o processo que uma CPU segue para armazenar o estado de uma thread antes de mudar de uma tarefa para outra, para que possa ser retomada do mesmo ponto posteriormente.
Impasses
Deadlocks são o problema mais temido que os desenvolvedores enfrentam ao escrever aplicativos simultâneos/multithread em python. A melhor maneira de entender os impasses é usando o problema clássico de exemplo de ciência da computação conhecido como Problema dos Filósofos de Jantar.
A declaração do problema para os filósofos do jantar é a seguinte:
Cinco filósofos estão sentados em uma mesa redonda com cinco pratos de espaguete (um tipo de macarrão) e cinco garfos, como mostra o diagrama.
python
- Função free() na biblioteca C:Como usar? Aprenda com o Exemplo
- Função Python String strip () com EXEMPLO
- Python String count() com EXEMPLOS
- Função Python round() com EXEMPLOS
- Função Python map() com EXEMPLOS
- Python Timeit() com exemplos
- Contador Python em coleções com exemplo
- Python List count() com EXEMPLOS
- Python List index() com exemplo
- C# - Multithreading