Python使用多进程并行加速业务操作 完整代码

简介: Python使用多进程并行加速业务操作 完整代码

Python使用多进程并行加速业务操作 完整代码






需求分析


  最近在对一个数据集进行处理,共2000条,每条去调一个第三方接口,耗时7-10秒。单线程处理一次要3.9-5.6小时,于是想着用多进程加速一下。 需求大致如下:


 1、能配置进程数目


 2、能加载要处理的数据


 3、能打印完善的日志


 4、多进程能共享处理后的数据结果,方便最终获取/导出


完整代码


  Python代码如下:(其中需要修改的地方加了TODO)在win和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.xlsx里面的数据是随便打的:


image.png


本demo性能分析


  16核CPU,执行上述代码,其中任务部分用了time.sleep(1)停了1秒,耗时分析如下:


进程数 耗时
1 29.317383289337158秒
4 8.288025140762329秒
8 5.77861475944519秒
14 4.941734313964844秒
16 5.262717008590698秒


可以看到加了多进程,加速效果还是比较明显的。


Python中单线程、多线程和多进程的效率对比实验


此处参考:http://blog.atomicer.cn/2016/09/30/Python


 我们知道,线程操作、进程操作一般分为CPU密集型操作、IO密集型操作、网络请求密集型操作。


 资料显示,如果多线程的进程是CPU密集型的,那多线程并不能有多少效率上的提升,相反还可能会因为线程的频繁切换,导致效率下降,推荐使用多进程;如果是IO密集型,多线程进程可以利用IO阻塞等待时的空闲时间执行其他线程,提升效率。所以我们根据实验对比不同场景的效率:


image.png


通过上面的结果,我们可以看到:


 多线程在IO密集型的操作下似乎也没有很大的优势(也许IO操作的任务再繁重一些就能体现出优势),在CPU密集型的操作下明显地比单线程线性执行性能更差,但是对于网络请求这种忙等阻塞线程的操作,多线程的优势便非常显著了


 多进程无论是在CPU密集型还是IO密集型以及网络请求密集型(经常发生线程阻塞的操作)中,都能体现出性能的优势。不过在类似网络请求密集型的操作上,与多线程相差无几,但却更占用CPU等资源,所以对于这种情况下,我们可以选择多线程来执行。

相关文章
|
12天前
|
缓存 监控 测试技术
Python中的装饰器:功能扩展与代码复用的利器###
本文深入探讨了Python中装饰器的概念、实现机制及其在实际开发中的应用价值。通过生动的实例和详尽的解释,文章展示了装饰器如何增强函数功能、提升代码可读性和维护性,并鼓励读者在项目中灵活运用这一强大的语言特性。 ###
|
15天前
|
缓存 开发者 Python
探索Python中的装饰器:简化代码,增强功能
【10月更文挑战第35天】装饰器在Python中是一种强大的工具,它允许开发者在不修改原有函数代码的情况下增加额外的功能。本文旨在通过简明的语言和实际的编码示例,带领读者理解装饰器的概念、用法及其在实际编程场景中的应用,从而提升代码的可读性和复用性。
|
13天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
11天前
|
Python
探索Python中的装饰器:简化代码,提升效率
【10月更文挑战第39天】在编程的世界中,我们总是在寻找使代码更简洁、更高效的方法。Python的装饰器提供了一种强大的工具,能够让我们做到这一点。本文将深入探讨装饰器的基本概念,展示如何通过它们来增强函数的功能,同时保持代码的整洁性。我们将从基础开始,逐步深入到装饰器的高级用法,让你了解如何利用这一特性来优化你的Python代码。准备好让你的代码变得更加优雅和强大了吗?让我们开始吧!
19 1
|
16天前
|
设计模式 缓存 监控
Python中的装饰器:代码的魔法增强剂
在Python编程中,装饰器是一种强大而灵活的工具,它允许程序员在不修改函数或方法源代码的情况下增加额外的功能。本文将探讨装饰器的定义、工作原理以及如何通过自定义和标准库中的装饰器来优化代码结构和提高开发效率。通过实例演示,我们将深入了解装饰器的应用,包括日志记录、性能测量、事务处理等常见场景。此外,我们还将讨论装饰器的高级用法,如带参数的装饰器和类装饰器,为读者提供全面的装饰器使用指南。
|
12天前
|
存储 缓存 监控
掌握Python装饰器:提升代码复用性与可读性的利器
在本文中,我们将深入探讨Python装饰器的概念、工作原理以及如何有效地应用它们来增强代码的可读性和复用性。不同于传统的函数调用,装饰器提供了一种优雅的方式来修改或扩展函数的行为,而无需直接修改原始函数代码。通过实际示例和应用场景分析,本文旨在帮助读者理解装饰器的实用性,并鼓励在日常编程实践中灵活运用这一强大特性。
|
16天前
|
存储 算法 搜索推荐
Python高手必备!揭秘图(Graph)的N种风骚表示法,让你的代码瞬间高大上
在Python中,图作为重要的数据结构,广泛应用于社交网络分析、路径查找等领域。本文介绍四种图的表示方法:邻接矩阵、邻接表、边列表和邻接集。每种方法都有其特点和适用场景,掌握它们能提升代码效率和可读性,让你在项目中脱颖而出。
28 5
|
14天前
|
机器学习/深度学习 数据采集 人工智能
探索机器学习:从理论到Python代码实践
【10月更文挑战第36天】本文将深入浅出地介绍机器学习的基本概念、主要算法及其在Python中的实现。我们将通过实际案例,展示如何使用scikit-learn库进行数据预处理、模型选择和参数调优。无论你是初学者还是有一定基础的开发者,都能从中获得启发和实践指导。
31 2
|
16天前
|
数据库 Python
异步编程不再难!Python asyncio库实战,让你的代码流畅如丝!
在编程中,随着应用复杂度的提升,对并发和异步处理的需求日益增长。Python的asyncio库通过async和await关键字,简化了异步编程,使其变得流畅高效。本文将通过实战示例,介绍异步编程的基本概念、如何使用asyncio编写异步代码以及处理多个异步任务的方法,帮助你掌握异步编程技巧,提高代码性能。
51 4
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
下一篇
无影云桌面