Resumo : neste tutorial, você aprenderá como usar o módulo de threading Python para desenvolver aplicativos multithread.
Aplicativos de thread único
Vamos começar com um programa simples:
from time import sleep, perf_counter
def task():
print('Starting a task...')
sleep(1)
print('done')
start_time = perf_counter()
task()
task()
end_time = perf_counter()
print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Como funciona.
Primeiro, importe as funções sleep()
e perf_counter()
do time
módulo:
from time import sleep, perf_counter
Linguagem de código: Python ( python )
Segundo, defina uma função que leva um segundo para ser concluída:
def task():
print('Starting a task...')
sleep(1)
print('done')
Linguagem de código: Python ( python )
Terceiro, obtenha o valor do contador de desempenho chamando a perf_counter()
função:
start_time = perf_counter()
Linguagem de código: Python ( python )
Quarto, chame a task()
função duas vezes:
task()
task()
Linguagem de código: Python ( python )
Quinto, obtenha o valor do contador de desempenho chamando a perf_counter()
função:
end_time = perf_counter()
Linguagem de código: Python ( python )
Por fim, imprima o tempo que leva para concluir a execução da task()
função duas vezes:
print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Aqui está o resultado:
Starting a task...
done
Starting a task...
done
It took 2.00 second(s) to complete.
Linguagem de código: Python ( python )
Como você pode esperar, o programa leva cerca de dois segundos para ser concluído. Se você chamar a task()
função 10 vezes, levará cerca de 10 segundos para ser concluída.
O diagrama a seguir ilustra como o programa funciona:
Primeiro, a task()
função é executada e dorme por um segundo. Em seguida, ele é executado pela segunda vez e também dorme por mais um segundo. Finalmente, o programa é concluído.
Quando a task()
função chama a sleep()
função, a CPU fica ociosa. Em outras palavras, a CPU não faz nada, o que não é eficiente em termos de utilização de recursos.
Este programa possui um processo com um único thread, que é chamado de thread principal . Como o programa possui apenas um thread, ele é chamado de programa de thread único.
Usando threading Python para desenvolver um exemplo de programa multithread
Para criar um programa multithread, você precisa usar o threading
módulo Python.
Primeiro, importe a Thread
classe do threading
módulo:
from threading import Thread
Linguagem de código: Python ( python )
Segundo, crie um novo thread instanciando uma instância da Thread
classe:
new_thread = Thread(target=fn,args=args_tuple)
Linguagem de código: Python ( python )
O Thread()
aceita muitos parâmetros. Os principais são:
target
: especifica uma função (fn
) para ser executada no novo thread.args
: especifica os argumentos da função (fn
). Oargs
argumento é uma tupla.
Terceiro, inicie o thread chamando o start()
método da Thread
instância:
new_thread.start()
Linguagem de código: Python ( python )
Se quiser esperar a conclusão do thread no thread principal, você pode chamar o join()
método:
new_thread.join()
Linguagem de código: Python ( python )
Ao chamar o join()
método, o thread principal aguardará a conclusão do thread filho antes de ser encerrado.
O programa a seguir ilustra como usar o threading
módulo:
from time import sleep, perf_counter
from threading import Thread
def task():
print('Starting a task...')
sleep(1)
print('done')
start_time = perf_counter()
# create two new threads
t1 = Thread(target=task)
t2 = Thread(target=task)
# start the threads
t1.start()
t2.start()
# wait for the threads to complete
t1.join()
t2.join()
end_time = perf_counter()
print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Como funciona. (e vamos nos concentrar apenas na parte de rosqueamento)
Primeiro, crie dois novos tópicos:
t1 = Thread(target=task)
t2 = Thread(target=task)
Segundo, inicie ambos os threads chamando o start()
método:
t1.start()
t2.start()
Linguagem de código: Python ( python )
Terceiro, aguarde a conclusão de ambos os threads:
t1.join()
t2.join()
Linguagem de código: Python ( python )
Finalmente, mostre o tempo de execução:
print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Saída:
Starting a task...
Starting a task...
done
done
It took 1.00 second(s) to complete.
Linguagem de código: Python ( python )
Quando o programa for executado, ele terá três threads: o thread principal e dois outros threads filhos.
Conforme mostrado claramente na saída, o programa levou um segundo em vez de dois para ser concluído.
O diagrama a seguir mostra como os threads são executados:
Passando argumentos para threads
O programa a seguir mostra como passar argumentos para a função atribuída a um thread:
from time import sleep, perf_counter
from threading import Thread
def task(id):
print(f'Starting the task {id}...')
sleep(1)
print(f'The task {id} completed')
start_time = perf_counter()
# create and start 10 threads
threads = []
for n in range(1, 11):
t = Thread(target=task, args=(n,))
threads.append(t)
t.start()
# wait for the threads to complete
for t in threads:
t.join()
end_time = perf_counter()
print(f'It took {end_time- start_time: 0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Como funciona.
Primeiro, defina uma task()
função que aceite um argumento:
def task(id):
print(f'Starting the task {id}...')
sleep(1)
print(f'The task {id} completed')
Linguagem de código: Python ( python )
Segundo, crie 10 novos threads e passe um ID para cada um. A threads
lista é usada para acompanhar todos os tópicos recém-criados:
threads = []
for n in range(1, 11):
t = Thread(target=task, args=(n,))
threads.append(t)
t.start()
Linguagem de código: Python ( python )
Observe que se você chamar o join()
método dentro do loop, o programa aguardará a conclusão do primeiro thread antes de iniciar o próximo.
Terceiro, espere que todos os threads sejam concluídos chamando o join()
método:
for t in threads:
t.join()
Linguagem de código: Python ( python )
O seguinte mostra a saída do programa:
Starting the task 1...
Starting the task 2...
Starting the task 3...
Starting the task 4...
Starting the task 5...
Starting the task 6...
Starting the task 7...
Starting the task 8...
Starting the task 9...
Starting the task 10...
The task 10 completed
The task 8 completed
The task 1 completed
The task 6 completed
The task 7 completed
The task 9 completed
The task 3 completed
The task 4 completed
The task 2 completed
The task 5 completed
It took 1.02 second(s) to complete.
Linguagem de código: Python ( python )
Demorou apenas 1,05 segundos para ser concluído.
Observe que o programa não executa o thread na ordem de 1 a 10.
Quando usar threading Python
Conforme apresentado no tutorial de processo e thread , existem dois tipos principais de tarefas:
- Tarefas vinculadas a E/S – o tempo gasto em E/S é significativamente maior do que o tempo gasto em computação.
- Tarefas vinculadas à CPU – o tempo gasto em computação é significativamente maior do que o tempo de espera por E/S.
O threading Python é otimizado para tarefas vinculadas a E/S. Por exemplo, solicitar recursos remotos, conectar um servidor de banco de dados ou ler e gravar arquivos.
Um exemplo prático de threading em Python
Suponha que você tenha uma lista de arquivos de texto em uma pasta, por exemplo, C:/temp/
. E você deseja substituir um texto por um novo em todos os arquivos.
O seguinte programa de thread único mostra como substituir uma substring pela nova nos arquivos de texto:
from time import perf_counter
def replace(filename, substr, new_substr):
print(f'Processing the file {filename}')
# get the contents of the file
with open(filename, 'r') as f:
content = f.read()
# replace the substr by new_substr
content = content.replace(substr, new_substr)
# write data into the file
with open(filename, 'w') as f:
f.write(content)
def main():
filenames = [
'c:/temp/test1.txt',
'c:/temp/test2.txt',
'c:/temp/test3.txt',
'c:/temp/test4.txt',
'c:/temp/test5.txt',
'c:/temp/test6.txt',
'c:/temp/test7.txt',
'c:/temp/test8.txt',
'c:/temp/test9.txt',
'c:/temp/test10.txt',
]
for filename in filenames:
replace(filename, 'ids', 'id')
if __name__ == "__main__":
start_time = perf_counter()
main()
end_time = perf_counter()
print(f'It took {end_time- start_time :0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Saída:
It took 0.16 second(s) to complete.
Linguagem de código: Python ( python )
O programa a seguir tem a mesma funcionalidade. No entanto, ele usa vários threads:
from threading import Thread
from time import perf_counter
def replace(filename, substr, new_substr):
print(f'Processing the file {filename}')
# get the contents of the file
with open(filename, 'r') as f:
content = f.read()
# replace the substr by new_substr
content = content.replace(substr, new_substr)
# write data into the file
with open(filename, 'w') as f:
f.write(content)
def main():
filenames = [
'c:/temp/test1.txt',
'c:/temp/test2.txt',
'c:/temp/test3.txt',
'c:/temp/test4.txt',
'c:/temp/test5.txt',
'c:/temp/test6.txt',
'c:/temp/test7.txt',
'c:/temp/test8.txt',
'c:/temp/test9.txt',
'c:/temp/test10.txt',
]
# create threads
threads = [Thread(target=replace, args=(filename, 'id', 'ids'))
for filename in filenames]
# start the threads
for thread in threads:
thread.start()
# wait for the threads to complete
for thread in threads:
thread.join()
if __name__ == "__main__":
start_time = perf_counter()
main()
end_time = perf_counter()
print(f'It took {end_time- start_time :0.2f} second(s) to complete.')
Linguagem de código: Python ( python )
Saída:
Processing the file c:/temp/test1.txt
Processing the file c:/temp/test2.txt
Processing the file c:/temp/test3.txt
Processing the file c:/temp/test4.txt
Processing the file c:/temp/test5.txt
Processing the file c:/temp/test6.txt
Processing the file c:/temp/test7.txt
Processing the file c:/temp/test8.txt
Processing the file c:/temp/test9.txt
Processing the file c:/temp/test10.txt
It took 0.02 second(s) to complete.
Linguagem de código: Python ( python )
Como você pode ver claramente na saída, o programa multithread é executado muito mais rápido.
Resumo
- Use o módulo Python
threading
para criar um aplicativo multithread. - Use o
Thread(function, args)
para criar um novo tópico. - Chame o
start()
método daThread
classe para iniciar o thread. - Chame o
join()
método daThread
classe para aguardar a conclusão do thread no thread principal. - Use threading apenas para aplicativos de processamento vinculados a E/S.