Python usa paralelismo multiprocesso para acelerar o código completo da operação de negócios

análise de demanda

   Recentemente, estou processando um conjunto de dados com um total de 2.000 registros. Leva de 7 a 10 segundos para ajustar uma interface de terceiros para cada registro. O processamento de thread único leva de 3,9 a 5,6 horas por vez, então pensei em usar vários processos para acelerá-lo. Os requisitos são mais ou menos os seguintes:

  1. O número de processos pode ser configurado
  2. Os dados a serem processados ​​podem ser carregados
  3. Um log completo pode ser impresso
  4. Múltiplos processos podem compartilhar os resultados dos dados processados, o que é conveniente para a aquisição/exportação final.
  5. Bloqueio, controle de tempo limite e controle de exceção

código completo

  O código Python é o seguinte: (os lugares que precisam ser modificados são adicionados TODO) Pode ser usado tanto no win quanto no linux

import logging
import math
import multiprocessing
import time
import pandas as pd
from contextlib import contextmanager
import threading

# 设置日志配置
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.INFO)


# 定义超时异常
class TimeoutException(Exception): pass


# 超时控制
@contextmanager
def time_limit(seconds):
    timer = threading.Timer(seconds, lambda: _raise_timeout_exception())

    def _raise_timeout_exception():
        raise TimeoutException("Timed out!")

    try:
        timer.start()
        yield
    finally:
        timer.cancel()


def process_data(i, data, results, lock):
    logging.info('------group: ' + str(i) + '------')
    logging.info('------len: ' + str(len(data)) + '------')
    for _, row in data.iterrows():
        if _ % (math.ceil(len(data) / 10.0)) == 0:
            logging.info('------group' + str(i) + ': ' + str(_) + '/' + str(len(data)) + '------')
        try:
            # 超时限制 TODO 秒数
            with time_limit(20):
                # 模拟任务 TODO 任务
                time.sleep(1)
                # 使用锁来保证对结果列表的进程安全访问
                lock.acquire()
                try:
                    # 将结果添加到共享的结果列表中 TODO 收集结果
                    results.append(row['id'])
                finally:
                    lock.release()
        except Exception as e:
            logging.info('------err: ' + str(e) + '------')


if __name__ == '__main__':
    # 手动设置并行进程数目 TODO 进程数目
    group_num = 8
    # 从电脑配置中设置并行进程数目
    # group_num = multiprocessing.cpu_count()

    # 读取数据 TODO 数据源
    data = pd.read_excel('data.xlsx')
    # 使用pandas平均划分数据
    grouped_data = data.groupby(data.index % group_num)

    # 定义共享的结果列表
    manager = multiprocessing.Manager()
    results = manager.list()

    # 创建锁
    lock = multiprocessing.Lock()

    start_time = time.time()

    # 定义多进程
    processes = []
    for i in range(group_num):
        p = multiprocessing.Process(target=process_data,
                                    args=(i, grouped_data.get_group(i).reset_index(), results, lock))
        processes.append(p)

    # 启动
    for _p in processes:
        _p.start()
    for _p in processes:
        _p.join()

    end_time = time.time()
    execution_time = end_time - start_time

    # 打印数据
    print(f"代码执行时间:{
      
      execution_time}秒")
    print(results)

  data.xlsxOs dados dentro são digitados casualmente:

Adicione uma descrição da imagem

Análise de desempenho desta demonstração

  A CPU de 16 núcleos executa o código acima e a parte da tarefa é interrompida por time.sleep(1)1 segundo. A análise demorada é a seguinte:

número de processos demorado
1 29,317383289337158 segundos
4 8,288025140762329 segundos
8 5,77861475944519 segundos
14 4,941734313964844 segundos
16 5,262717008590698 segundos

  Pode-se ver que com a adição de múltiplos processos, o efeito de aceleração é bastante óbvio.

Experimento de comparação de eficiência de single-thread, multi-thread e multi-processo em Python

Referência aqui: http://blog.atomicer.cn/2016/09/30/Python

  Sabemos que as operações de encadeamento e as operações de processo geralmente são divididas em operações intensivas de CPU, operações intensivas de E/S e operações intensivas de solicitação de rede.

  De acordo com os dados, se o processo multithread for intensivo em CPU, o multithreading não melhorará muito a eficiência. Pelo contrário, a troca frequente de threads pode levar a uma diminuição da eficiência. É recomendável usar multi -process; se for intensivo em IO, os processos multithread podem usar o tempo ocioso quando o IO é bloqueado para executar outros threads para melhorar a eficiência. Então, comparamos a eficiência de diferentes cenários com base em experimentos:

Operação intensiva da CPU operações intensivas de IO Operações intensivas em solicitações de rede
operação linear 94.91824996469 22.46199995279 7.3296000004
operação multiencadeada 101.1700000762 24.8605000973 0,5053332647
operação multi-processo 53.8899999857 12.7840000391 0,5045000315

  Através dos resultados acima, podemos ver:

  Multi-threading não parece ter uma grande vantagem em operações intensivas de IO (talvez as tarefas de operação IO mais pesadas possam refletir as vantagens) e é obviamente pior do que o desempenho de execução linear de thread único em operações intensivas de CPU. solicitações, que estão ocupadas esperando para bloquear threads, as vantagens do multithreading são muito significativas.

  Quer seja intensivo em CPU, IO intensivo ou intensivo em solicitações de rede (operações em que o bloqueio de encadeamento geralmente ocorre), o multiprocesso pode mostrar vantagens de desempenho. No entanto, em termos de operações intensivas em solicitações de rede, é quase o mesmo que multi-threading, mas consome mais recursos, como CPU, portanto, neste caso, podemos escolher multi-threading para executar.

Acho que você gosta

Origin blog.csdn.net/qq_43592352/article/details/131085684
Recomendado
Clasificación