Multiprocessamento Python – 03

Resumo : neste tutorial, você aprenderá como executar código em paralelo usando o módulo de multiprocessamento Python.

Introdução ao multiprocessamento Python

Geralmente, os programas lidam com dois tipos de tarefas:

  1. Tarefas vinculadas a E/S: se uma tarefa realiza muitas operações de entrada/saída, ela é chamada de tarefa vinculada a E/S. Exemplos típicos de tarefas vinculadas a E/S são ler arquivos, gravar em arquivos, conectar-se a bancos de dados e fazer uma solicitação de rede. Para tarefas vinculadas a E/S, você pode usar multithreading para acelerá-las.
  2. Tarefas vinculadas à CPU: quando uma tarefa realiza muitas operações usando uma CPU, ela é chamada de tarefa vinculada à CPU. Por exemplo, cálculo de números, redimensionamento de imagens e streaming de vídeo são tarefas vinculadas à CPU. Para acelerar o programa com muitas tarefas vinculadas à CPU, você usa multiprocessamento.

O multiprocessamento permite que dois ou mais processadores processem simultaneamente duas ou mais partes diferentes de um programa.

Em Python, você usa o multiprocessingmódulo para implementar multiprocessamento.

Exemplo de multiprocessamento Python

Veja o seguinte programa:

import time

def task():
    result = 0
    for _ in range(10**8):
        result += 1
    return result

if __name__ == '__main__':
    start = time.perf_counter()
    task()
    task()
    finish = time.perf_counter()

    print(f'It took {finish-start:.2f} second(s) to finish')Linguagem de código:  Python  ( python )

Saída:

It took  5.55 second(s) to finishLinguagem de código:  Python  ( python )

Como funciona.

Primeiro, definir a task()função é uma tarefa vinculada à CPU porque ela executa um cálculo pesado executando um loop por 100 milhões de iterações e incrementando uma variável result:

def task():
    result = 0
    for _ in range(10**8):
        result += 1
    return resultLinguagem de código:  Python  ( python )

Segundo, chame as task()funções duas vezes e registre o tempo de processamento:

if __name__ == '__main__':
    start = time.perf_counter()
    task()
    task()
    finish = time.perf_counter()

    print(f'It took {finish-start: .2f} second(s) to finish')Linguagem de código:  Python  ( python )

Em nosso computador, demorou 5,55 segundos para ser concluído.

Usando módulo de multiprocessamento

O programa a seguir usa o módulo de multiprocessamento, mas leva menos tempo:

import time
import multiprocessing

def task() -> int:
    result = 0
    for _ in range(10**8):
        result += 1
    return result

if __name__ == '__main__':
    start = time.perf_counter()

    p1 = multiprocessing.Process(target=task)
    p2 = multiprocessing.Process(target=task)

    p1.start()
    p2.start()

    p1.join()
    p2.join()

    finish = time.perf_counter()
    print(f'It took {finish-start:.2f} second(s) to finish')Linguagem de código:  Python  ( python )

Saída:

It took  3.43 second(s) to finishLinguagem de código:  Python  ( python )

Como funciona.

Primeiro, importe o módulo de multiprocessamento:

import multiprocessingLinguagem de código:  Python  ( python )

Segundo, crie dois processos e passe a função de tarefa para cada um:

p1 = multiprocessing.Process(target=task)
p2 = multiprocessing.Process(target=task)Linguagem de código:  Python  ( python )

Observe que o Process()construtor retorna um novo Processobjeto.

Terceiro, chame o start()método dos Processobjetos para iniciar o processo:

p1.start()
p2.start()Linguagem de código:  Python  ( python )

Por fim, aguarde a conclusão dos processos chamando o join()método:

p1.join()
p2.join()Linguagem de código:  Python  ( python )

Exemplo prático de multiprocessamento Python

Usaremos o módulo de multiprocessamento para redimensionar as imagens de alta resolução.

Primeiro, instale a Pillowbiblioteca para processamento de imagens:

pip install PillowLinguagem de código:  Python  ( python )

Segundo, desenvolva um programa que crie miniaturas das imagens na imagespasta e salve-as na thumbspasta:

import time
import os
from PIL import Image, ImageFilter

filenames = [
    'images/1.jpg',
    'images/2.jpg',
    'images/3.jpg',
    'images/4.jpg',
    'images/5.jpg',
]

def create_thumbnail(filename, size=(50,50), thumb_dir ='thumbs'):
    # open the image
    img = Image.open(filename)
    
    # apply the gaussian blur filter
    img = img.filter(ImageFilter.GaussianBlur())

    # create a thumbnail
    img.thumbnail(size)
    
    # save the image
    img.save(f'{thumb_dir}/{os.path.basename(filename)}')

    # display a message
    print(f'{filename} was processed...')


if __name__ == '__main__':
    start = time.perf_counter()

    for filename in filenames:
        create_thumbnail(filename)
        
    finish = time.perf_counter()

    print(f'It took {finish-start:.2f} second(s) to finish')Linguagem de código:  Python  ( python )

Em nosso computador, demorou cerca de 4,06 segundos para ser concluído:

images/1.jpg was processed...
images/2.jpg was processed...
images/3.jpg was processed...
images/4.jpg was processed...
images/5.jpg was processed...
It took 4.06 second(s) to finishLinguagem de código:  Python  ( python )

Terceiro, modifique o programa para usar multiprocessamento. Cada processo criará uma miniatura para uma imagem:

import time
import os
from PIL import Image, ImageFilter

import multiprocessing

filenames = [
    'images/1.jpg',
    'images/2.jpg',
    'images/3.jpg',
    'images/4.jpg',
    'images/5.jpg',
]

def create_thumbnail(filename, size=(50,50), thumb_dir ='thumbs'):
    # open the image
    img = Image.open(filename)
    
    # apply the gaussian blur filter
    img = img.filter(ImageFilter.GaussianBlur())

    # create a thumbnail
    img.thumbnail(size)
    
    # save the image
    img.save(f'{thumb_dir}/{os.path.basename(filename)}')

    # display a message
    print(f'{filename} was processed...')

def main():
    start = time.perf_counter()

    # create processes
    processes = [multiprocessing.Process(target=create_thumbnail, args=[filename]) 
                for filename in filenames]

    # start the processes
    for process in processes:
        process.start()

    # wait for completion
    for process in processes:
        process.join()

    finish = time.perf_counter()

    print(f'It took {finish-start:.2f} second(s) to finish')


if __name__ == '__main__':
    main()Linguagem de código:  Python  ( python )

Saída:

images/5.jpg was processed...
images/4.jpg was processed...
images/1.jpg was processed...
images/3.jpg was processed...
images/2.jpg was processed...
It took 2.92 second(s) to finishLinguagem de código:  Python  ( python )

Nesse caso, a saída mostra que o programa processou as imagens mais rapidamente.

Resumo

  • Use o multiprocessamento Python para executar código em paralelo para lidar com tarefas vinculadas à CPU.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *