Multithreading em Python | Conjunto 1
Este artigo cobre os fundamentos de multithreading na linguagem de programação Python. Assim como o multiprocessamento , o multithreading é uma forma de realizar multitarefa. Em multithreading, o conceito de threads é usado.
Vamos primeiro entender o conceito de thread na arquitetura de computador.
Fio
Na computação, um processo é uma instância de um programa de computador que está sendo executado. Qualquer processo tem 3 componentes básicos:
- Um programa executável.
- Os dados associados necessários para o programa (variáveis, espaço de trabalho, buffers, etc.)
- O contexto de execução do programa (estado do processo)
Um thread é uma entidade dentro de um processo que pode ser agendada para execução. Além disso, é a menor unidade de processamento que pode ser executada em um SO (Sistema Operacional).
Em palavras simples, um thread é uma sequência de tais instruções dentro de um programa que pode ser executado independentemente de outro código. Para simplificar, você pode assumir que um thread é simplesmente um subconjunto de um processo!
Um thread contém todas essas informações em um Thread Control Block (TCB) :
- Identificador de thread: ID exclusivo (TID) é atribuído a cada novo thread
- Ponteiro de pilha: aponta para a pilha do thread no processo. Stack contém as variáveis locais no escopo do thread.
- Contador de programa: um registro que armazena o endereço da instrução atualmente em execução por thread.
- Estado do thread: pode estar em execução, pronto, esperando, iniciar ou concluído.
- Conjunto de registros do thread: registros atribuídos ao thread para cálculos.
- Ponteiro de processo pai: Um ponteiro para o bloco de controle de processo (PCB) do processo em que o thread reside.
Considere o diagrama abaixo para entender a relação entre o processo e seu encadeamento:
Multithreading
Vários threads podem existir dentro de um processo onde:
- Cada thread contém seu próprio conjunto de registros e variáveis locais (armazenadas na pilha) .
- Todas as threads de um processo compartilham variáveis globais (armazenadas em heap) e o código do programa .
Considere o diagrama abaixo para entender como vários threads existem na memória:
Multithreading é definido como a capacidade de um processador de executar vários threads simultaneamente.
Em uma CPU simples de núcleo único, isso é obtido usando a alternância frequente entre threads. Isso é denominado como troca de contexto . Na troca de contexto, o estado de um thread é salvo e o estado de outro thread é carregado sempre que ocorre qualquer interrupção (devido a I / O ou manualmente). A troca de contexto ocorre com tanta frequência que todos os threads parecem estar executando paralelamente (isso é denominado como multitarefa ).
Considere o diagrama abaixo, no qual um processo contém dois threads ativos:
Multithreading em Python
Em Python, o módulo de threading fornece uma API muito simples e intuitiva para gerar vários threads em um programa.
Vamos considerar um exemplo simples usando o módulo de threading:
import
threading
def
print_cube(num):
(
"Cube: {}"
.
format
(num
*
num
*
num))
def
print_square(num):
(
"Square: {}"
.
format
(num
*
num))
if
__name__
=
=
"__main__"
:
t1
=
threading.Thread(target
=
print_square, args
=
(
10
,))
t2
=
threading.Thread(target
=
print_cube, args
=
(
10
,))
t1.start()
t2.start()
t1.join()
t2.join()
(
"Done!"
)
Quadrado: 100 Cubo: 1000 Feito!
Vamos tentar entender o código acima:
- Para importar o módulo de threading, fazemos:
importar threading
- Para criar um novo thread, criamos um objeto da classe Thread . Leva os seguintes argumentos:
- alvo : a função a ser executada por thread
- args : os argumentos a serem passados para a função de destino
No exemplo acima, criamos 2 threads com funções de destino diferentes:
t1 = threading.Thread (target = print_square, args = (10,)) t2 = threading.Thread (target = print_cube, args = (10,))
- Para iniciar um thread, usamos o método start de Thread classe .
t1.start() t2.start()
- Depois que os threads são iniciados, o programa atual (você pode pensar nele como um thread principal) também continua em execução. A fim de parar a execução do programa atual até que um thread seja concluído, usamos join método de .
t1.join() t2.join()
Como resultado, o programa atual primeiro aguardará a conclusão de t1 e depois t2 . Depois de concluídas, as instruções restantes do programa atual são executadas.
Considere o diagrama abaixo para uma melhor compreensão de como funciona o programa acima:
Considere o programa python fornecido a seguir, no qual imprimimos o nome do thread e o processo correspondente para cada tarefa:
import
threading
import
os
def
task1():
(
"Task 1 assigned to thread: {}"
.
format
(threading.current_thread().name))
(
"ID of process running task 1: {}"
.
format
(os.getpid()))
def
task2():
(
"Task 2 assigned to thread: {}"
.
format
(threading.current_thread().name))
(
"ID of process running task 2: {}"
.
format
(os.getpid()))
if
__name__
=
=
"__main__"
:
(
"ID of process running main program: {}"
.
format
(os.getpid()))
(
"Main thread name: {}"
.
format
(threading.current_thread().name))
t1
=
threading.Thread(target
=
task1, name
=
't1'
)
t2
=
threading.Thread(target
=
task2, name
=
't2'
)
t1.start()
t2.start()
t1.join()
t2.join()
ID do processo executando o programa principal: 11758 Nome do tópico principal: MainThread Tarefa 1 atribuída ao tópico: t1 ID do processo em execução na tarefa 1: 11758 Tarefa 2 atribuída ao tópico: t2 ID do processo em execução na tarefa 2: 11758
Vamos tentar entender o código acima:
- Usamos a função os.getpid() para obter a ID do processo atual.
print ("ID do processo executando o programa principal: {}". format (os.getpid()))
Como fica claro na saída, o ID do processo permanece o mesmo para todos os threads.
- Usamos a função threading.main_thread() para obter o objeto thread principal. Em condições normais, a thread principal é a thread a partir da qual o interpretador Python foi iniciado. O atributo name do objeto thread é usado para obter o nome do thread.
print ("Nome do thread principal: {}". format (threading.main_thread(). name))
- Usamos a função threading.current_thread() para obter o objeto thread atual.
print ("Tarefa 1 atribuída ao tópico: {}". format (threading.current_thread(). nome))
O diagrama abaixo esclarece o conceito acima:
Portanto, esta foi uma breve introdução ao multithreading em Python. O próximo artigo desta série cobre a sincronização entre vários threads .
Multithreading em Python | Conjunto 2 (sincronização)
Este artigo foi contribuído por Nikhil Kumar . Se você gosta de GeeksforGeeks e gostaria de contribuir, você também pode escrever um artigo usando contribute.geeksforgeeks.org ou enviar o seu artigo para contribute@geeksforgeeks.org. Veja o seu artigo que aparece na página principal do GeeksforGeeks e ajude outros Geeks.
Escreva comentários se encontrar algo incorreto ou se quiser compartilhar mais informações sobre o tópico discutido acima.
As postagens do blog Acervo Lima te ajudaram? Nos ajude a manter o blog no ar!
Faça uma doação para manter o blog funcionando.
70% das doações são no valor de R$ 5,00...
Diógenes Lima da Silva