当前位置:   article > 正文

python多线程线程池的map和starmap对比_python starmap

python starmap

python多线程线程池的map和starmap对比

map和starmap都是多线程中同步执行的方法,二者的差别在于用map函数放入线程池的任务只能接受一个参数;用starmap函数放入线程池的任务则可以接受多个参数。这样看来,starmap函数其实比map函数更好用。

下面是案例分析(注意每个代码段里job函数的参数数量、使用的是map还是starmap)。

使用map函数,任务只接受一个参数

import multiprocessing as mp
import numpy as np

def job(x): # 在此案例中,目标函数(即后面提到的“任务”)就是job函数,后面会将job函数放入进程池
  return x * x
  
def multicore():
  # 创建进程池
  # pool = mp.Pool() # 默认使用所有CPU核
  pool = mp.Pool(processes = 2) # 使用processes指定使用的CPU核的数量
    
  args = np.arange(10) # 创建10次任务的参数
  res = pool.map(job, args) # map可以一次接收多次任务的参数,但是每次任务只能接收1个参数
  print(res) # 输出结果长度为10,对应10次任务的运行结果

if __name__ == "__main__":
    multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

使用map函数,任务接受的参数数量大于一个

import multiprocessing as mp
import numpy as np

# 在此案例中,目标函数(即后面提到的“任务”)就是job函数,后面会将job函数放入进程池
def job(x, y): # 与前一个案例相比,job函数有所修改:在此案例中job函数接收2个参数
  return x * y
  
def multicore():
  # 创建进程池
  # pool = mp.Pool() # 默认使用所有CPU核
  pool = mp.Pool(processes = 2) # 使用processes指定使用的CPU核的数量
    
  args = [(1, 2), (3, 4), (5, 6)] # 创建3次任务的参数,每次任务接收2个参数
  res = pool.map(job, args) # map可以一次接收多次任务的参数,每次任务只能接收1个参数。但是args中每次任务都给了2个参数,所以这个案例会报错
  print(res) # 报错,无法输出结果

if __name__ == "__main__":
    multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上面这个案例会报错,因为使用map函数将任务放入进程池时,这个任务只能接收1个参数。那么如何修改?这里给出两类修改方案。

修改方案一:改用starmap函数

import multiprocessing as mp

def job(x, y): # 用starmap函数将任务放进进程池时,任务可以接收一个及以上的参数
  return x * y

def multicore():
  # pool = mp.Pool() # 默认使用所有CPU核
  pool = mp.Pool(processes = 2) # 使用processes指定使用的CPU核的数量
    
  args = [(1, 2), (3, 4)]
  res = pool.starmap(job, args) # starmap也可以一次接收多次任务的参数,并且每次任务的参数可以不止1个
  print(res)

multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

修改方案二:对任务进行修改,在任务内部对参数进行“解压”

import multiprocessing as mp

def job(args): # 用map函数将任务放进进程池时,任务只能接收一个参数
  x, y = args # 这个例子就是job函数的运行本来需要接收2个参数,但是用map函数将job任务放进进程池,那就只能先将2个参数放进一个元组里形成1个参数,然后在job函数里再将2个参数分开来
  return x * y

def multicore():
  # pool = mp.Pool() # 默认使用所有CPU核
  pool = mp.Pool(processes = 2) # 使用processes指定使用的CPU核的数量
  
  args = [(1, 2), (3, 4)]
  res = pool.map(job, args) # map可以一次接收多次任务的参数,但是每次任务接收的参数只能是1个。(1, 2)为第一次任务的参数(虽然看起来传了2个参数,但实际上是作为一个元组,所以是只传了1个参数),(3, 4)为第二次任务的参数(一个元组)
  print(res)

if __name__ == "__main__":
    multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这个方法的局限是要求目标函数/任务可以被修改。

修改方案三:使用偏函数partial在任务外修改函数

from functools import partial
import multiprocessing as mp

# 在此案例中,目标函数(即后面提到的“任务”)就是job函数,后面会将job函数放入进程池
def job(x, y): # 在此案例中job函数接收2个参数
  return x * y
  
def multicore():
  # 创建进程池
  # pool = mp.Pool() # 默认使用所有CPU核
  pool = mp.Pool(processes = 2) # 使用processes指定使用的CPU核的数量
  
  job2 = partial(job, y = 2) # 使用partial函数,将job函数的其中一个参数固定取值为2,返回一个新函数,这个函数相当于只需要接收1个参数.新函数的名字不能与原函数的名字相同,否则会报错
  args = [1, 2, 3] # 创建3次任务的参数,这个参数是未被固定取值的参数
  res = pool.map(job2, args)
  print(res) # [2, 4, 6]

if __name__ == "__main__":
    multicore()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

偏函数partial的作用是:把一个函数的某些参数给固定住(也就是设置默认值),这样得到的是一个跟原函数功能相同的一个新函数,调用这个新函数只需要提供那些未被固定的参数即可。

这个方法的局限是要求任务的多个参数中的其中一个参数为固定值。

关于partial函数的解释可以参考文章:彻底明白 Python partial()

参考:python多线程用法_multiprocessing

这篇文章介绍了同步和异步的执行、map和starmap使用区别。但是介绍map和starmap使用区别所用的案例不够清晰。

Multiprocessing Pool map() Multiple Arguments

这篇文章介绍了python多线程中进程池的map()函数如何在需要使用多参数的情况下应用。文章介绍了4种解决方法:①使用apply_async();**②使用starmap();**③修改目标函数,在目标函数中对参数组“解压”以分出多个参数;④使用wrapper函数对参数组“解压”。

我只看了③这种解决方案。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/181348
推荐阅读
相关标签
  

闽ICP备14008679号