multiprocess模块使用进程池时往Pool对象传入的函数不巧当导致进程运行速度跟单线程速度一样

本文详细介绍了Python中multiprocessing.pool模块的Pool类及其关键方法,如apply_async和map_async的功能与用法。强调了如何正确提交任务到进程池以实现并发执行,并通过实例对比了不同方式下任务执行效率的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pythonmultiprocessing.pool 模块里有 Pool 类用于进程池管理,Pool 实例中一些比较重要的方法:

  • apply_async(func, args, kwargs, callback)

    • 往进程池异步提交任务,即任务提交到进程池后可以不用等任务结果可以继续往下运行;与其对立的是任务提交后,提交任务的进程会被阻塞直到任务被执行完返回结果
    • 参数func是必须的,args用于提供给 func的参数,args类型为 元组kwargs 也是提供给 func函数的参数, callback 任务执行完后立刻执行的回调函数,callback函数禁止执行任何阻塞操作
  • map_async(func, iterable, chunksize, callback)

    • 参数 chunksizecallback 是可选的
    • 将可迭代对象iterable的每一个元素作为参数传递给func并异步地执行函数,返回结果是 AsyncResult 类的实例
    • 如果提供 callback 参数,当返回结果变得可用时立即执行 callback 函数
  • close( )

    • 关闭进程池防止进一步操作,关闭后将不再接受任务
  • join( )

    • 等待所有工作进程退出,join( ) 只能在close( )方法或terminate( )方法调用后再调用

往进程池里扔任务里调用 apply_async() 方法,该方法第一个参数传递的是函数名如果传入一个函数,函数将不会并发地执行;比如有个无参函数名字为 doMatch ,但往 apply_async() 方法传递的第一个参数如果是doMatch(),那么提交到进程池的任务将不会并发执行


如果往apply_async() 方法传递的是函数而不是函数名,提交的任务将不会被并发执行,并且返回结果也是错误的

以下是未正确提交任务到进程池的代码

import ctypes
import datetime
import random

import time

from multiprocessing import Queue
from multiprocessing.pool import Pool

from multiprocessing import Value

def doMatch():
    s = "0123456789abcdefghijklmnopqrstuvwxyz"
    index = random.randint(0, len(s) - 4)
    time.sleep(1)
    return s[index:index + 2]


if __name__ == '__main__':
    param = "0123456789abcdefghijklmnopqrstuvwxyz"
    val = Value(ctypes.c_uint32, 1)
    index = 1
    queue = Queue()

    # 测试单进程执行 doMatch() 函数30次需要的时间
    start = datetime.datetime.now()
    for i in range(30):
        print("single process:\t{}".format(doMatch()))
    finish = datetime.datetime.now()
    print("\n单线程执行花费的时间为:\t{}".format(finish - start))

    # 测试9个进程的进程池执行 doMatch() 函数30次需要的时间
    reslist = []
    pool1 = Pool(9)
    start = datetime.datetime.now()
    for i in range(30):
        res = pool1.apply_async(doMatch())
        # e = entry(param)
        # res = pool1.apply_async(e.exec, callback=e.display)
        reslist.append(res)
    pool1.close()
    pool1.join()
    finish = datetime.datetime.now()
    # print("result = \n{}".format(reslist))
    for res in reslist:
        print(res)

    print("9个进程的进程池执行花费的时间为:\t{}".format(finish - start))

    # 测试3组3个进程的进程池执行 doMatch() 函数30次需要的时间
    pool2 = Pool(3)
    pool3 = Pool(3)
    pool4 = Pool(3)
    pools = [pool2, pool3, pool4]

    index = 1

    reslist = []
    start = datetime.datetime.now()
    for j in range(len(pools)):
        for i in range(10):
            # e = entry(param)
            # pools[j].apply_async(e.exec)
            asyncresult = pools[j].apply_async(doMatch())
            reslist.append(asyncresult)

        pools[j].close()
    for j in range(len(pools)):
        pools[j].join()
    finish = datetime.datetime.now()
    print("3个3个进程的进程池执行花费的时间为:\t{}".format(finish - start))
    for result in reslist:
        print(result)

运行结果

这里写图片描述


修改传递给 apply_async() 的func参数为函数名再执行的结果:


这里写图片描述
这里写图片描述
这里写图片描述


总结

往进程池里提交任务时需要提交要执行的函数名,不能直接向函数调用那样直接提交这个函数及参数;

如果提交的任务需要额外带参数, apply_async() 的第二个参数用于接收提交任务所需要的参数,因此可以传递两个参数给 apply_async() 方法,第二个参数的类型要求为元组;

apply_async() 方法返回的结果为 AsyncResult 的实例,可以使用 get() 方法获取异步执行的结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值