Python进程池的简单使用

本文介绍Python中进程池的概念及其实现,并通过一个实用案例展示了如何封装进程池以提高多进程任务处理效率。

Python中有进程池的概念,相比线程池,更加稳定。在此基础上,进行一个简单封装。

首先写一个工具类ProcessUtil.py

#!/user/bin/env python3
# -*- coding: utf-8 -*-
from multiprocessing.pool import Pool


class TaskAction(object):
    def do_in_action(self):
        pass


class TaskProcess(object):
    def __init__(self, core_size=None):
        if core_size is None:
            self.pool = Pool()
        else:
            if type(core_size) is not int:
                raise ValueError('core_size can\'t handle type  %s ,only int support ' % type(core_size))
            self.pool = Pool(core_size)

    # 检查task参数有效性
    @staticmethod
    def _check_task(tasks):
        # check tasks type is list ?
        if type(tasks) is not list:
            raise ValueError('tasks can\'t handle type %s , only list support' % type(tasks))
        # check tasks' subset is TaskAction ?
        for child_task in tasks:
            if not isinstance(child_task, TaskAction):
                raise ValueError(
                    'tasks\' subset can\'t handle type %s , only TaskAction support' % type(child_task))

    # 异步执行进程
    def execute_task(self, tasks):
        apply_results = []
        # check params
        self._check_task(tasks)
        # 添加任务至进程池
        for child_task in tasks:
            apply_results.append(self.pool.apply_async(child_task.do_in_action))
        # 拒绝添加新的Process
        self.pool.close()
        # 等待所有子进程执行完毕
        self.pool.join()
        # 封装请求结果
        results = []
        for res in apply_results:
            results.append(res.get())
        return results

然后是一个测试case:

#!/user/bin/env python3
# -*- coding: utf-8 -*-
import json
import os
import random
# 进程的试炼
import time
import unittest

from util import DateUtil
from util import ProcessUtil


class ProcessTest(unittest.TestCase):
    def setUp(self):
        print('============================= %s is ready to start...' % self._testMethodName)

    def tearDown(self):
        print('============================= %s had finished...' % self._testMethodName)

    def test_04(self):
        list = []
        # 构造任务列
        for i in range(100):
            user_id = i + 1
            access_token = DateUtil.DateParser.parse_stamp_second(DateUtil.DateParser.now()) + user_id + random.randint(
                10, 99)
            list.append(DemoTest(user_id, access_token))
        # 执行任务列
        result = ProcessUtil.TaskProcess(3).execute_task(list)
        print('All sub processes done.')
        print(json.dumps(result))


class DemoTest(ProcessUtil.TaskAction):
    def __init__(self, user_id, access_token):
        self.user_id = user_id
        self.access_token = access_token

    def do_in_action(self):
        second = random.random() * 3
        time.sleep(second)
        print('UserId : %s , AccessToken : %s , (%s) ' % (self.user_id, self.access_token, os.getpid()))
        return second


if __name__ == '__main__':
    unittest.main()
控制台部分打印信息:

UserId : 90 , AccessToken : 1504516412.0 , (15272) 
UserId : 88 , AccessToken : 1504516457.0 , (7456) 
UserId : 91 , AccessToken : 1504516405.0 , (15272) 
UserId : 92 , AccessToken : 1504516425.0 , (7456) 
UserId : 89 , AccessToken : 1504516452.0 , (7096) 
UserId : 93 , AccessToken : 1504516471.0 , (15272) 
UserId : 96 , AccessToken : 1504516435.0 , (15272) 
UserId : 97 , AccessToken : 1504516460.0 , (15272) 
UserId : 98 , AccessToken : 1504516439.0 , (15272) 
UserId : 94 , AccessToken : 1504516455.0 , (7456) 
UserId : 95 , AccessToken : 1504516454.0 , (7096) 
UserId : 100 , AccessToken : 1504516402.0 , (7456) 
UserId : 99 , AccessToken : 1504516426.0 , (15272) 
.
----------------------------------------------------------------------
Ran 1 test in 48.824s
从结果上看 进程设置了3个进程 分别在 7456 ,7096,15272 三个pid上运行,提高了效率

最后吐槽下,java中实现线程池好累,要关心池的配置,资源释放,类型校验等等


<think>我们被要求回答关于Python进程池使用方法及示例。根据引用内容,我们可以从多个角度来讲解。 引用[1]提到进程池是multiprocessing模块提供的用于管理进程的方式。 引用[2]和[3]提供了进程池的示例代码。 引用[4]指出进程池适用于CPU密集型任务,而线程池适用于I/O密集型任务。 引用[5]展示了使用进程池时如何传递参数和收集结果。 我们将从以下几个方面进行说明: 1. 创建进程池 2. 提交任务的方法:apply_async(异步提交)、apply(同步提交)、map、imap等 3. 获取任务结果 4. 关闭进程池并等待任务完成 5. 使用上下文管理器(with语句)管理进程池 6. 异常处理 注意:由于用户之前询问的是线程池,现在转向进程池,我们可以对比一下两者的适用场景(根据引用[4])。 示例代码将参考引用[2]、[3]、[5]进行整合,并添加详细注释。 另外,我们还需要注意,在Windows系统上使用多进程时,必须将代码放在`if __name__ == '__main__':`中,以避免子进程递归执行。 下面开始组织回答。</think>### Python进程池使用方法详解 进程池适用于**CPU密集型任务**(如数学计算、图像处理),可绕过GIL限制充分利用多核CPU。以下是核心用法及示例(基于`multiprocessing.Pool`): --- #### 1. 基础使用流程 ```python from multiprocessing import Pool import os def task(x): print(f"进程 {os.getpid()} 处理任务 {x}") return x * x # 模拟CPU计算 if __name__ == '__main__': with Pool(processes=4) as pool: # 创建4个进程的池 results = pool.map(task, range(10)) # 批量提交任务 print("计算结果:", results) ``` **输出示例**: ``` 进程 1234 处理任务 0 进程 1235 处理任务 1 进程 1236 处理任务 2 进程 1237 处理任务 3 ... 计算结果: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] ``` --- #### 2. 异步任务处理 使用`apply_async`实现非阻塞提交: ```python def task(x): return x ** 2 if __name__ == '__main__': with Pool(4) as pool: futures = [pool.apply_async(task, (i,)) for i in range(5)] results = [f.get(timeout=10) for f in futures] # 超时获取结果 print(results) # [0, 1, 4, 9, 16] ``` --- #### 3. 进程间共享数据 通过`Manager`实现跨进程数据共享: ```python from multiprocessing import Pool, Manager def worker(x, shared_list): shared_list.append(x * x) return x if __name__ == '__main__': with Manager() as manager: shared_list = manager.list() # 共享列表 with Pool(2) as pool: # 传递共享对象到子进程 pool.starmap(worker, [(i, shared_list) for i in range(5)]) print("共享结果:", list(shared_list)) # [0, 1, 4, 9, 16] ``` --- #### 4. 高级功能示例 **动态控制任务流**: ```python def task(x): if x % 2 == 0: return x * 2 else: raise ValueError(f"奇数错误: {x}") if __name__ == '__main__': with Pool(2) as pool: try: # 使用imap_unordered获取结果(按完成顺序) for res in pool.imap_unordered(task, range(5)): print("收到结果:", res) except Exception as e: print("捕获异常:", e) ``` --- ### 关键参数说明 | **方法** | **作用** | **适用场景** | |------------------|----------------------------------------|--------------------------| | `pool.map()` | 批量提交任务,按顺序返回结果 | 简单并行任务 | | `pool.apply_async()` | 异步提交单个任务,返回AsyncResult对象 | 需控制任务提交时机 | | `pool.starmap()` | 支持多参数的任务批量提交 | 参数为元组的任务 | | `pool.close()` | 禁止新任务加入 | 准备结束进程池 | | `pool.join()` | 阻塞等待所有任务完成 | 清理阶段使用 | --- ### 注意事项 1. **必须使用`if __name__ == '__main__'`** 避免Windows系统下的递归创建进程问题[^1] 2. **进程间通信成本高** 共享数据需通过`Manager`或`Queue`,避免直接传递大对象 3. **进程池初始化开销大** 适合长时间运行的任务,短任务可能适得其反 4. **异常处理** 子进程异常需在主进程捕获(如示例4) > 对比线程池:进程池适用于CPU密集型任务,线程池适用于I/O密集型任务(如网络请求)[^4]。 --- ### 完整示例(带异常处理) ```python from multiprocessing import Pool import time def task(x): try: time.sleep(0.5) if x == 3: raise ValueError("特殊错误") return x * 2 except Exception as e: return f"任务失败: {str(e)}" if __name__ == '__main__': with Pool(3) as pool: results = [] # 提交10个任务 for i in range(10): future = pool.apply_async(task, (i,)) results.append(future) # 获取结果 for idx, f in enumerate(results): try: print(f"任务{idx}结果: {f.get(timeout=2)}") except Exception as e: print(f"任务{idx}超时或异常: {str(e)}") ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值