Exemplo de Multiprocessamento em Python

No nosso tutorial anterior, aprendemos sobre o Exemplo CSV em Python. Neste tutorial, vamos aprender sobre Multiprocessamento em Python com exemplos.

Multiprocessamento em Python

O processamento paralelo está recebendo mais atenção atualmente. Se você ainda não sabe sobre processamento paralelo, aprenda na Wikipedia. À medida que os fabricantes de CPU continuam adicionando mais e mais núcleos aos seus processadores, criar código paralelo é uma ótima maneira de melhorar o desempenho. O Python introduziu o módulo multiprocessing para nos permitir escrever código paralelo. Para entender a principal motivação deste módulo, é necessário conhecer alguns conceitos básicos sobre programação paralela. Depois de ler este artigo, esperamos que você consiga reunir algum conhecimento sobre este tópico.

Processo Multiprocessamento em Python, Fila e Bloqueios

Existem várias classes no módulo de multiprocessamento do Python para construir um programa paralelo. Entre elas, três classes básicas são Process, Queue e Lock. Essas classes ajudarão você a construir um programa paralelo. Mas antes de descrever sobre elas, vamos iniciar este tópico com um código simples. Para tornar um programa paralelo útil, você precisa saber quantos núcleos existem no seu PC. O módulo de Multiprocessamento do Python permite que você saiba isso. O seguinte código simples imprimirá o número de núcleos no seu PC.

import multiprocessing

print("Number of cpu : ", multiprocessing.cpu_count())

A saída seguinte pode variar para o seu PC. Para mim, o número de núcleos é 8.

Classe de Processo do Multiprocessamento do Python

A classe Process de multiprocessamento do Python é uma abstração que configura outro processo Python, fornece a ele código para executar e uma maneira para o aplicativo pai controlar a execução. Existem duas funções importantes pertencentes à classe Process – a função start() e a função join(). Primeiro, precisamos escrever uma função que será executada pelo processo. Em seguida, precisamos instanciar um objeto de processo. Se criarmos um objeto de processo, nada acontecerá até que o instruamos a começar o processamento por meio da função start(). Em seguida, o processo será executado e retornará seu resultado. Depois disso, dizemos ao processo para ser concluído por meio da função join(). Sem a chamada da função join(), o processo permanecerá inativo e não será encerrado. Portanto, se você criar muitos processos e não os encerrar, poderá enfrentar escassez de recursos. Então, você pode precisar encerrá-los manualmente. Uma coisa importante é que, se você quiser passar algum argumento através do processo, precisa usar o argumento de palavra-chave args. O código a seguir será útil para entender o uso da classe Process.

from multiprocessing import Process


def print_func(continent='Asia'):
    print('The name of continent is : ', continent)

if __name__ == "__main__":  # confirms that the code is under main function
    names = ['America', 'Europe', 'Africa']
    procs = []
    proc = Process(target=print_func)  # instantiating without any argument
    procs.append(proc)
    proc.start()

    # instanciando processo com argumentos
    for name in names:
        # print(name)
        proc = Process(target=print_func, args=(name,))
        procs.append(proc)
        proc.start()

    # completando os processos
    for proc in procs:
        proc.join()

O resultado do seguinte código será:

Classe de fila de multiprocessamento Python

Você tem conhecimentos básicos sobre estrutura de dados de computador, provavelmente conhece sobre Fila. O módulo de Multiprocessamento do Python fornece a classe Fila, que é exatamente uma estrutura de dados Primeiro a Entrar, Primeiro a Sair (FIFO). Elas podem armazenar qualquer objeto Python pickle (embora os simples sejam os melhores) e são extremamente úteis para compartilhar dados entre processos. Filas são especialmente úteis quando passadas como parâmetro para a função alvo de um Processo para permitir que o Processo consuma dados. Usando a função put(), podemos inserir dados na fila e, usando get(), podemos obter itens das filas. Veja o código a seguir para um exemplo rápido.

from multiprocessing import Queue

colors = ['red', 'green', 'blue', 'black']
cnt = 1
# instanciando um objeto fila
queue = Queue()
print('pushing items to queue:')
for color in colors:
    print('item no: ', cnt, ' ', color)
    queue.put(color)
    cnt += 1

print('\npopping items from queue:')
cnt = 0
while not queue.empty():
    print('item no: ', cnt, ' ', queue.get())
    cnt += 1

Classe Bloqueio do Multiprocessamento Python

A tarefa da classe Bloqueio é bastante simples. Ela permite que o código reivindique o bloqueio para que nenhum outro processo possa executar o código semelhante até que o bloqueio tenha sido liberado. Portanto, a tarefa da classe Bloqueio é principalmente duas. Uma é reivindicar o bloqueio e a outra é liberar o bloqueio. Para reivindicar o bloqueio, a função acquire() é usada e para liberar o bloqueio, a função release() é usada.

Exemplo de Multiprocessamento em Python

Neste exemplo de multiprocessamento em Python, iremos juntar todo o nosso conhecimento. Suponha que temos algumas tarefas para realizar. Para concluir essa tarefa, iremos usar vários processos. Portanto, iremos manter duas filas. Uma conterá as tarefas e a outra conterá o registro das tarefas concluídas. Em seguida, instanciamos os processos para concluir a tarefa. Observe que a classe Queue do Python já está sincronizada. Isso significa que não precisamos usar a classe Lock para bloquear vários processos para acessar o mesmo objeto de fila. Portanto, não precisamos usar a classe Lock neste caso. Abaixo está a implementação onde estamos adicionando tarefas à fila, então criando processos e iniciando-os, depois usando join() para concluir os processos. Finalmente, estamos imprimindo o registro da segunda fila.

from multiprocessing import Lock, Process, Queue, current_process
import time
import queue # imported for using queue.Empty exception


def do_job(tasks_to_accomplish, tasks_that_are_done):
    while True:
        try:
            '''
                try to get task from the queue. get_nowait() function will 
                raise queue.Empty exception if the queue is empty. 
                queue(False) function would do the same task also.
            '''
            task = tasks_to_accomplish.get_nowait()
        except queue.Empty:

            break
        else:
            '''
                if no exception has been raised, add the task completion 
                message to task_that_are_done queue
            '''
            print(task)
            tasks_that_are_done.put(task + ' is done by ' + current_process().name)
            time.sleep(.5)
    return True


def main():
    number_of_task = 10
    number_of_processes = 4
    tasks_to_accomplish = Queue()
    tasks_that_are_done = Queue()
    processes = []

    for i in range(number_of_task):
        tasks_to_accomplish.put("Task no " + str(i))

    # criando processos
    for w in range(number_of_processes):
        p = Process(target=do_job, args=(tasks_to_accomplish, tasks_that_are_done))
        processes.append(p)
        p.start()

    # completando processo
    for p in processes:
        p.join()

    # imprimir a saída
    while not tasks_that_are_done.empty():
        print(tasks_that_are_done.get())

    return True


if __name__ == '__main__':
    main()

Dependendo do número de tarefas, o código levará algum tempo para mostrar a saída. A saída do código a seguir variará de tempos em tempos.

Python multiprocessamento Pool

O Pool de multiprocessamento do Python pode ser usado para execução paralela de uma função em vários valores de entrada, distribuindo os dados de entrada entre os processos (paralelismo de dados). Abaixo está um exemplo simples de Pool de multiprocessamento em Python.

from multiprocessing import Pool

import time

work = (["A", 5], ["B", 2], ["C", 1], ["D", 3])


def work_log(work_data):
    print(" Process %s waiting %s seconds" % (work_data[0], work_data[1]))
    time.sleep(int(work_data[1]))
    print(" Process %s Finished." % work_data[0])


def pool_handler():
    p = Pool(2)
    p.map(work_log, work)


if __name__ == '__main__':
    pool_handler()

Abaixo está a imagem que mostra a saída do programa acima. Observe que o tamanho do pool é 2, então duas execuções da função work_log estão acontecendo em paralelo. Quando uma das funções de processamento termina, ela escolhe o próximo argumento e assim por diante. Então, é isso para o módulo de multiprocessamento do Python. Referência: Documentação Oficial

Source:
https://www.digitalocean.com/community/tutorials/python-multiprocessing-example