Python多进程处理方法(Pool、apply_async、map_async)

本文介绍Python中使用多进程实现并行处理的方法,包括进程池Pool类的常用处理方法及其样例代码,适用于需要提高程序执行效率的场景。
该文章已生成可运行项目,

由于Python的多线程并不能真正支持并行,实际上仍采用的是单核串行的方式,这与它的GIL(全局解释器锁)有关。因此,我们需要异步并行地执行某些程序时,可以采用多进程的方式。

多进程详细API可以参考链接:https://docs.python.org/zh-cn/3/library/multiprocessing.html,本文主要讲述其中的关键部分以及使用样例。

1、常用的进程池Pool类处理方法

1.1 apply(func[, args[, kwds]])

使用 args 参数以及 kwds 命名参数调用 func , 它会返回结果前阻塞。这种情况下,apply_async() 更适合并行化工作。另外 func 只会在一个进程池中的一个工作进程中执行。

1.2 apply_async(func[, args[, kwds[, callback[, error_callback]]]])

apply() 方法的一个变种,返回一个 AsyncResult 对象。

如果指定了 callback , 它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback 。

如果指定了 error_callback , 它必须是一个接受单个参数的可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。

回调函数应该立即执行完成,否则会阻塞负责处理结果的线程。

1.3 map(funciterable[, chunksize])

内置 map() 函数的并行版本 (但它只支持一个 iterable 参数,对于多个可迭代对象请参阅 starmap())。 它会保持阻塞直到获得结果。

这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而(近似)指定每个块的大小可以。

注意对于很长的迭代对象,可能消耗很多内存。可以考虑使用 imap() 或 imap_unordered() 并且显示指定 chunksize 以提升效率。

1.4 map_async(funciterable[, chunksize[, callback[, error_callback]]])

map() 方法的一个变种,返回一个 AsyncResult 对象。

如果指定了 callback , 它必须是一个接受单个参数的可调用对象。当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback 。

如果指定了 error_callback , 它必须是一个接受单个参数的可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。

回调函数应该立即执行完成,否则会阻塞负责处理结果的线程。

2、异步进程返回结果 AsyncResult 处理方法

AsyncResult 为 Pool.apply_async() 和 Pool.map_async() 返回对象所属的类。

get([timeout])

用于获取执行结果。如果 timeout 不是 None 并且在 timeout 秒内仍然没有执行完得到结果,则抛出 multiprocessing.TimeoutError 异常。如果远程调用发生异常,这个异常会通过 get() 重新抛出。

wait([timeout])

阻塞,直到返回结果,或者 timeout 秒后超时。

ready()

返回执行状态,是否已经完成。

successful()

判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError

在 3.7 版更改: 如果没有执行完,会抛出 ValueError  异常而不是 AssertionError 。

3、多进程处理样例

本例特点:可以异步执行,每个进程传入多个参数,并且完整获取到进程的多个返回值

from multiprocessing import Pool


def test(arg1, arg2):
    return "hello," + arg1, arg2 + ' test', [2222, 5, 356]


if __name__ == '__main__':
    p = Pool(2)
    results = []
    rslt1 = p.apply_async(test, ('world1', 'tea',))  # 异步执行进程1,传入两个参数
    results.append(rslt1)
    rslt2 = p.apply_async(test, ('world2', 'cat',))  # 异步执行进程2,传入两个参数
    results.append(rslt2)
    for r in results:
        a, b, c = r.get()  # 获取异步进程执行结果,返回值有三个
        print(a, b, c)

# 两个进程的结果输出分别为:
# hello,world1 tea test [2222, 5, 356]
# hello,world1 cat test [2222, 5, 356]

传多个参数推荐使用apply_async,如果采用map_async,无法通过p.map_async(test, ('world1', 'tea',))的方式传入多个参数 。

本文章已经生成可运行项目
<think>嗯,用户想了解Pythonapply_async函数的用法,需要提供示例。首先,我得回忆一下multiprocessing模块里的Poolapply_async的基本知识。apply_async属于非阻塞的方法,用于异步执行任务,记得它和apply的区别在于不会阻塞主进程。 用户可能需要知道如何创建进程池,然后使用apply_async提交任务。参数方面,apply_async第一个参数是函数名,然后是args元组,还可以有关键字参数比如callback和error_callback。回调函数在任务完成后处理结果,错误回调处理异常。 然后,示例代码应该展示基本用法,比如定义一个计算平方的函数,用apply_async提交,然后调用get()获取结果。但要注意,使用get()会阻塞,可能需要在适当的时候调用。同时,要提醒用户使用close()和join()来正确管理进程池。 另外,用户提供的引用里提到了callback的使用,比如在任务完成时打印结果。所以示例里应该包含回调函数的例子,比如定义一个my_callback函数,传递给apply_async。还可能提到多个任务提交后,如何等待所有任务完成,比如用get()逐个获取结果或者使用列表保存各个async对象。 可能需要注意的错误点,比如忘记关闭进程池,或者在回调函数中处理异常。引用中的问题,比如回调未被调用,可能和进程池未正确关闭或任务未完成有关,所以示例中要正确展示close()和join()的使用步骤。 还需要说明apply_asyncmap_async的区别,apply_async每次提交一个任务,而map_async可以处理可迭代的参数。不过用户的问题主要是apply_async,所以重点放在它的参数和回调上。 最后,考虑用户可能的应用场景,比如并行处理数据、批量计算等,可以举一个稍微复杂的例子,比如计算多个数字的平方,并汇总结果。同时提醒错误处理,比如使用error_callback来捕获异常。 总结步骤:导入Pool,定义函数,创建进程池,使用apply_async提交任务,处理回调,关闭进程池并等待完成。示例代码要简洁明了,注释清楚每个步骤的作用。相关问题可以涉及回调不执行的原因,性能优化,与其他方法的比较,以及错误处理等。</think>### Python `apply_async` 函数使用方法详解 `apply_async` 是 Python `multiprocessing.Pool` 模块中用于异步执行任务的函数,适用于多进程并行计算场景。以下是其核心用法和示例: --- ### **基本语法** ```python from multiprocessing import Pool # 创建进程池 with Pool(processes=N) as pool: # N为进程数 result = pool.apply_async( func, # 目标函数 args=(), # 函数参数(元组形式) callback=None, # 任务完成后的回调函数 error_callback=None # 任务出错的回调函数 ) # 获取结果(可选,会阻塞主进程) output = result.get() ``` --- ### **示例 1:基本用法** ```python from multiprocessing import Pool import time def square(x): time.sleep(1) # 模拟耗时操作 return x ** 2 if __name__ == "__main__": with Pool(processes=2) as pool: # 提交任务 async_result = pool.apply_async(square, (10,)) # 主进程继续执行其他操作 print("主进程执行中...") # 获取结果(阻塞直到任务完成) print("结果:", async_result.get()) # 输出: 结果: 100 ``` --- ### **示例 2:使用回调函数** ```python def my_callback(result): print(f"回调收到结果: {result}") if __name__ == "__main__": with Pool(2) as pool: # 提交任务并绑定回调 async_result = pool.apply_async( square, (5,), callback=my_callback ) pool.close() # 关闭进程池,不再接受新任务 pool.join() # 等待所有子进程完成 # 输出: 回调收到结果: 25 ``` --- ### **示例 3:多任务并行** ```python if __name__ == "__main__": with Pool(2) as pool: results = [] for i in range(3): # 提交3个任务 res = pool.apply_async(square, (i,)) results.append(res) # 获取所有结果 print([res.get() for res in results]) # 输出: [0, 1, 4] ``` --- ### **关键注意事项** 1. **非阻塞特性** `apply_async` 是异步的,提交任务后立即返回 `AsyncResult` 对象,需调用 `get()` 获取结果(会阻塞)[^1]。 2. **进程池管理** - 必须调用 `pool.close()` 和 `pool.join()` 确保所有任务完成[^2]。 - 使用 `with` 语句可自动管理资源。 3. **错误处理** 通过 `error_callback` 捕获异常: ```python def handle_error(error): print("任务出错:", error) pool.apply_async( error_prone_func, args=(...), error_callback=handle_error ) ``` --- ### **常见问题解答** - **回调函数未触发**:确保调用 `pool.join()` 或任务未提前终止[^2]。 - **性能优化**:调整进程数(通常等于 CPU 核心数)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值