二十四、Python多进程multiprocessing模块

「@Author: Runsen」
threading 包为 Python 提供了线程模型 , 而multiprocessing 包则为另一种并发模型 — 多进程模型提供了强大的解决方案 。
multiprocessingmultiprocessing包是Python中的多进程管理包 。 与之前的threading.Thread类似 , 它可以利用multiprocessing.Process对象来创建一个进程 。
multiprocessing的模块的API非常简单直观 , 可以让新手迅速上手在多个进程之间划分工作 。 我们现在看一个官方简单的例子:
# importing the multiprocessing module import multiprocessing def print_cube(num):print("Cube: {}".format(num * num * num)) def print_square(num):print("Square: {}".format(num * num)) if __name__ == "__main__":# creating processesp1 = multiprocessing.Process(target=print_square, args=(10, ))p2 = multiprocessing.Process(target=print_cube, args=(10, ))# starting process 1 --tt-darkmode-color: #3594F7;">multiprocessing模块 , 随后定义了两个函数 , 它们的功能分别是打印一个数的三次方和打印一个数的平方 。
之后关键的步骤来了 , 要创建多个进程 , 首先需要创建Process类的对象 。 在这个例子中Process类接收了两个参数:

  • target:在进程中被执行的函数
  • args:向被执行函数传递的参数
线程池ThreadPool类提供一个线程池 , 该线程池可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器 。
通常可导入模块:from multiprocessing import Pool 。
创建线程池:pool = Pool(10)
官方提供了比较常见的三种使用线程池的方法 。 分别是map , apply和apply_async 。
Map其中map规定线程池执行的任务:result = pool.map(func,datalist)
func为所要执行的函数 , datalist为参数列表 , 线程池也会依次在参数列表中提取参数带入函数中来执行函数 , 参数列表的长度也就是线程池所要执行的任务数量 。
# 进程池即创建一个进程库 , 事先设置好需要多少进程 , 从进程库中提取这些已创建的进程即可 。 # Pool.map()import multiprocessingdef test(i):print(i)if __name__ == '__main__':list1 = list(range(5))# 创建一个列表 , map方法会用到pool1 = multiprocessing.Pool(processes=4)# 创建一个进程池 , 这里创建了含有4个进程的进程池pool1.map(test, list1)'''对pool1使用map方法 , 在这个例子中即形成(test(0),test(1),test(2),test(3),test(4) 这些任务)这些将执行的任务是按顺序执行的 , 也就是说进程1执行test(0) , 进程2执行test(1) , 进程3执行test(2) ,进程4执行test(3) , 还多出一个任务则需要等待 , 等到某个进程提前结束了就再执行这个任务 。这样的话相当于一个进程执行一次单独的任务 , 十分方便某些任务如果函数有返回值即return , 还可以使用result = pool1.map(test,list1)获取每个进程的返回值 ,但是这里是所有返回值在一起 , 需要自己对其按需处理 。'''pool1.close()# close方法用于关闭进程池 , 即恢复到没有子进程的情况pool1.join()除了map方法 , 还有apply和apply_async方法用来执行进程 , 允许多个进程同时进入池子 。
apply在multiprocessing模块中 , apply阻塞主进程, 并且一个一个按顺序地执行子进程, 等到全部子进程都执行完毕后 ,继续执行apply()后面主进程的代码 。
import timeimport multiprocessingdef doIt(num):print("Process num is : %s" % num)time.sleep(1)print('process%s end' % num)if __name__ == '__main__':print('mainProcess start')# 记录一下开始执行的时间start_time = time.time()# 创建三个子进程pool = multiprocessing.Pool(3)print('Child start')for i in range(3):pool.apply(doIt, [i])print('mainProcess done time:%s s' % (time.time() - start_time))pool.close()pool.join()输出如下所示
mainProcess startChild startProcess num is : 0process0 endProcess num is : 1process1 endProcess num is : 2process2 endmainProcess done time:3.7142281532287598 s执行结果 我们可以看到, 主进程开始执行之后, 创建的三个子进程也随即开始执行, 主进程被阻塞, 而且接下来三个子进程是一个接一个按顺序地执行, 等到子进程全部执行完毕之后, 主进程就会继续执行, 打印出最后一句 。
apply_async接下来是使用apply_async(), 只需要把上面的代码使用apply()的地方改成apply_async() 即可, 代码如下 。
import timeimport multiprocessingdef doIt(num):print("Process num is : %s" % num)time.sleep(1)print('process%s end' % num)if __name__ == '__main__':print('mainProcess start')# 记录一下开始执行的时间start_time = time.time()# 创建三个子进程pool = multiprocessing.Pool(3)print('Child start')for i in range(3):pool.apply_async(doIt, [i])print('mainProcess done time:%s s' % (time.time() - start_time))pool.close()pool.join()输出如下所示