Python 面试题:并行编程

  • 一般想要处理cpu 密集型的任务会选择 multiprocessing 模块来进行加速。要想发挥出 multiprocessing 模块的优势,最好是通过 concurrent.futures 模块及其 ProcessPoolExecutor 类来编写代码,因为这样做比较简单。
  • 只有在其他方案全都无效的情况下,才可以考虑直接使用 multiprocessing 里面的高级功能(那些功能用起来相当复杂)

根据以下代码说明 concurrent.futures 模块里面的 ProcessPoolExecutor 类的实现原理

import my_module
from concurrent.futures import ProcessPoolExecutor
import time

NUMBERS = [ ... ]

def main():
    start = time.time()
    pool = ProcessPoolExecutor(max_workers=2)   # The one change
    results = list(pool.map(my_module.gcd, NUMBERS))
    end = time.time()
    delta = end - start
    print(f'Took {delta:.3f} seconds')

if __name__ == '__main__':
    main()

1)从包含输入数据的 NUMBERS 列表里把每个元素取出来,以便交给 map。
2)用 pickle 模块对每个元素做序列化处理,把它转成二进制形式
3)将序列化之后的数据,从主解释器所在的进程经由本地 socket 复制到子解释器所在的进程。
4)在子进程里面,用 pickle 模块对数据做反序列化处理,把它还原成 Python 对象。
5)引入包含 gcd 函数的那个 Python 模块。
6)把刚才还原出来的那个对象交给 gcd 函数去处理,此时,其他子进程也可以把它们各自的那份数据交给它们各自的 gcd 函数执行。
7)对执行结果做序列化处理,把它转化成二进制形式。
8)将二进制数据通过 socket 复制到上级进程。
9)在上级进程里面对二进制数据做反序列化处理,把它还原成 Python 对象。
10)把每条子进程所给出的结果都还原好,最后合并到一个 list里面返回。

concurrent.futures.ProcessPoolExecutor 的局限性

  • 上级进程与子进程之间做全套的序列化与反序列化处理开销很大。
  • 只适合孤立的而且数据利用度较高的任务。所谓孤立(isolated),这里指每一部分任务都不需要跟程序里的其他部分共用状态信息。所谓数据利用度较高(high-leverage),这里指任务所使用的原始材料以及最终所给出的结果数据量都很小,因此上级进程与子进程之间只需要互传很少的信息就行。
posted @   profound-wu  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示