paint-brush
Compreendendo multiprocessamento e multithreading em Pythonpor@pragativerma
10,354 leituras
10,354 leituras

Compreendendo multiprocessamento e multithreading em Python

por Pragati Verma6m2022/08/22
Read on Terminal Reader
Read this story w/o Javascript

Muito longo; Para ler

Multithreading e multiprocessamento são as duas formas mais comuns de obter simultaneidade e paralelização. Poucos desenvolvedores entendem a diferença entre eles e não conseguem escolher qual usar. Neste artigo, estaremos discutindo as diferenças. Podemos usar o módulo Threading Python para entender e implementar o conceito. O módulo de encadeamento oferece uma API intuitiva para gerar facilmente vários encadeamentos que podem ser usados quando houver necessidade de mais poder de processamento. Para fazer isso, você terá que usar algo conhecido como **Lock** ou **Global Interpreter Lock em Python.

Company Mentioned

Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Compreendendo multiprocessamento e multithreading em Python
Pragati Verma HackerNoon profile picture


Multithreading e Multiprocessing são as duas formas mais comuns de obter simultaneidade e paralelização, no entanto, poucos desenvolvedores entendem a diferença entre eles e falham em escolher efetivamente qual usar e quando.


Neste artigo, discutiremos as diferenças entre multithreading e multiprocessamento e como decidir o que usar e como implementá-lo em Python.


O que é um fio?

Um thread é um fluxo independente de execução. Pode ser visto essencialmente como um componente individual leve de um processo, que pode ser executado paralelamente. Threading é um recurso geralmente fornecido pelo sistema operacional. Pode haver vários threads em um processo, que compartilham o mesmo espaço de memória, o que significa que eles compartilham o código a ser executado e as variáveis declaradas no programa entre si.


Para entender isso melhor, vamos considerar um exemplo dos programas em execução em seu laptop agora. Você provavelmente está lendo este artigo com várias abas abertas em seu navegador. Enquanto isso, você tem o aplicativo de desktop Spotify aberto para ouvir música. Agora, o navegador e o aplicativo de desktop Spotify são como dois processos distintos que podem empregar vários processos ou threads para alcançar o paralelismo. Portanto, as diferentes guias do seu navegador podem ser executadas em diferentes threads. Da mesma forma, o Spotify pode reproduzir música usando um thread e usar outro para baixar sua música favorita da Internet e usar um terceiro para exibir a interface do usuário. E isso é chamado Multithreading.


O que é Multithreading em Python?

Multithreading, como o nome sugere, é uma tarefa ou operação que pode executar vários threads ao mesmo tempo. É uma técnica popular que agiliza várias tarefas em rápida sucessão ao mesmo tempo e facilita o compartilhamento rápido e fácil de recursos entre vários encadeamentos com o encadeamento principal.


A imagem a seguir explica o Multithreading em Python:



Python é uma linguagem linear, mas podemos usar o módulo Threading Python para entender e implementar o conceito de Multithreading em Python. O módulo de encadeamento oferece uma API intuitiva para gerar facilmente vários encadeamentos que podem ser usados quando houver necessidade de mais poder de processamento.


Pode ser usado como mostrado abaixo:


 import threading from queue import Queue import time def testThread(num): print num if __name__ == '__main__': for i in range(5): t = threading.Thread(target=testThread, arg=(i,)) t.start()


No trecho de código acima, target é usado como o objeto que pode ser chamado, args para passar parâmetros para a função e start para iniciar o thread.


Agora, aqui vem algo interessante - a fechadura.


Bloqueio de intérprete global

Muitas vezes, há casos na programação em que você deseja que seus encadeamentos possam modificar ou usar as variáveis comuns aos encadeamentos. No entanto, para fazer isso, você terá que usar algo conhecido como Lock ou Global Interpreter Lock (GIL) em Python.


do Python wiki :


No CPython, o global interpreter lock , ou GIL , é um mutex que protege o acesso a objetos Python, impedindo que vários threads executem bytecodes Python de uma só vez. Esse bloqueio é necessário principalmente porque o gerenciamento de memória do CPython não é thread-safe.


No nível do interpretador, o Python basicamente serializa as instruções. Para que qualquer thread execute qualquer função, ela deve primeiro obter um bloqueio global. Como apenas um thread pode obter esse bloqueio por vez, o interpretador deve finalmente executar as instruções em série. Essa arquitetura torna o gerenciamento de memória thread-safe, mas não pode usar vários núcleos de CPU.


Simplificando, sempre que uma função deseja usar ou modificar uma variável, ela bloqueia essa variável de forma que, se qualquer outra função quiser usar ou modificar essa variável específica, ela terá que esperar até que essa variável seja desbloqueada.


Considere duas funções que iteram uma variável por um. Você pode usar o bloqueio para garantir que uma função possa ler a variável, executar cálculos e escrever de volta antes que outra função possa, para que possamos evitar corrupção de dados.


Casos de uso para multithreading em Python

Threading em Python é mais útil para operações de E/S ou tarefas vinculadas à rede, como a execução de scripts, por exemplo, no caso de web scraping, em vez de tarefas que podem exigir muito da CPU. Outro exemplo é o Tensorflow , que usa um pool de threads para transformar dados em paralelo.


Além desses aplicativos, as Interfaces Gráficas do Usuário (GUIs) usam Multithreading o tempo todo para tornar os aplicativos responsivos e interativos. Um exemplo comum pode ser um programa de edição de texto onde, assim que o usuário insere o texto, ele é exibido na tela. Aqui, uma thread cuida da entrada do usuário enquanto a outra lida com a tarefa de exibi-la. Podemos adicionar mais tópicos para mais funcionalidades, como verificação ortográfica, preenchimento automático e assim por diante.


Agora, tendo discutido os threads em detalhes, vamos passar para os processos.


O que é um processo?

Um processo é simplesmente uma instância do programa de computador que está sendo executado. Cada processo tem seu próprio espaço de memória que é usado para armazenar as instruções que estão sendo executadas e quaisquer dados que precise acessar ou armazenar para a execução do código. Por causa disso, gerar um processo é mais demorado e lento em comparação com um thread.


Como discutimos anteriormente, quando estamos executando vários aplicativos em nosso desktop, cada aplicativo é um processo e quando estamos executando esses processos ao mesmo tempo, é chamado de Multiprocessamento.


O que é multiprocessamento em Python?

Multiprocessamento é a capacidade de um processador executar várias tarefas não relacionadas simultaneamente. Ele permite que você crie programas que podem ser executados simultaneamente, ignorando o Global Interpreter Lock (GIL) e usando todo o núcleo da CPU para execução eficiente de tarefas.


Embora o conceito de multiprocessamento seja fundamentalmente diferente do multithreading, sua sintaxe ou uso em Python é bastante semelhante. Semelhante ao módulo Threading, temos um módulo Multiprocessing em Python que auxilia na geração de diferentes processos, onde cada processo possui seu próprio interpretador Python e um GIL.



Como os processos não compartilham a mesma memória, eles não podem modificar a mesma memória simultaneamente, evitando o risco de entrar em um impasse ou chances de corrupção de dados.


Pode ser usado como mostrado abaixo:


 import multiprocessing def spawn(num): print(num) if __name__ == '__main__': for i in range(5): p = multiprocessing.Process(target=spawn, args=(i,)) p.start() p.join() # this line allows you to wait for processes


Casos de uso para multiprocessamento em Python

Como discutimos anteriormente, o multiprocessamento é uma escolha mais sábia caso as tarefas sejam extensas da CPU e não tenham nenhuma operação de E/S ou interações do usuário.


Diferenças, Méritos e Desvantagens

Aqui estão alguns pontos para resumir as diferenças, méritos e desvantagens do Multiprocessamento e Multithreading:

  • Threads compartilham o mesmo espaço de memória enquanto cada processo tem seu próprio espaço de memória.
  • Compartilhar objetos entre encadeamentos é mais simples, mas você deve tomar precauções extras para a sincronização de objetos para garantir que dois encadeamentos não gravem no mesmo objeto ao mesmo tempo e que não surja uma condição de corrida.
  • A programação multithreaded é mais propensa a bugs do que o multiprocessamento devido à sobrecarga de programação adicionada para sincronização de objetos.
  • O processo de geração é mais demorado e consome mais recursos do que os threads, pois eles têm uma sobrecarga menor do que os processos.
  • Os threads não podem alcançar o paralelismo completo aproveitando vários núcleos de CPU devido a restrições GIL em Python. Não existem tais restrições com multiprocessamento.
  • O sistema operacional lida com o agendamento de processos, enquanto o interpretador Python lida com o agendamento de threads.
  • Os processos filhos podem ser interrompidos e eliminados, mas as threads filhas não. Você deve esperar que os encadeamentos terminem ou se juntem.


Multiprocessamento x Multithreading

Conclusão

Podemos tirar as seguintes conclusões dessa discussão:

  • O encadeamento é recomendado para programas que precisam de E/S ou interação do usuário.
  • Para aplicativos com uso intensivo de computação e limitados por CPU, o multiprocessamento deve ser empregado.


Agora que você entende como o multiprocessamento e o multithreading do Python operam e como eles se comparam, você pode escrever código de forma eficaz e aplicar as duas abordagens em várias circunstâncias.


Espero que você tenha achado este artigo útil. Continue lendo!