LAST UPDATE: July 17th 2018, 10:31:00 PM

John Reese - Thinking Outside the GIL with AsyncIO and Multiprocessing - PyCon 2018
给出了异步IO和多进程相结合的想法和实现

Multiprocessing

  • Scales with CPU cores
  • Automatic IPC
  • Pool.map is really useful

多进程,每个进程有自己的GIL,可以避开限制实现真正的并发;
提供多种IPC渠道:Queue, Pipe…
自带接口非常nice,比如Pool.map

  • One task per process
  • Beware forking, pickling

每个进程实际上受到自己的GIL限制,只能运行一个任务
多进程处理时应注意内存复制导致内存占用过高问题

asyncio

  • Based on futures
  • Faster than threads
  • Massive I/O concurrency

基于future -> 可以很好地和一些C++库配合使用

  • Processing still limited by GIL
  • Beware timeuts and queue length

asyncio是在单个进程的层面上,受到GIL的限制
如果异步队列过长,协程可能会在执行之前就超时

multiprocessing + asyncio

  • Use multiprocessing primitives
  • Event loop per process
  • Queues for work/results
  • Highly parallel workload
  • Need to do some plumbing

每个进程运行独立的事件循环,把进程并发和异步IO结合起来

Optimizations
  • Multiple work queues
  • Combine tasks into batches
  • Use spawned processes

multiprocessing.Queue内部有锁,单一时间内只能进行读或写,如果有多个子进程访问,可以分割数据后存储在多个队列
将多个任务组成一个批次传进进程
使用衍生进程,只继承必要的资源,相比fork和forkserver避免大量的内存占用,但启动速度更慢

Considerations
  • Minimize what you pickle
  • prechunk work items
  • Aggregate results in the child
  • Use map/reduce

减小pickle的规模,因为父子进程间消息传递需要pickle和unpickle
一些需要切成块状的数据可以预处理
子进程返回的数据可以适当进行合并
运用MapReduce

性能对比

benchmark

https://raw.githubusercontent.com/jreese/aiomultiprocess/master/aiomultiprocess/core.py

引Nasy学姐说的一句:

多进程更多的原因是,单进程计算量不够,而异步则是因为一些 IO 或者 网络之类的拖慢了整体的速度。这样的一个任务是一个即是计算密集也是 IO 密集的(很奇怪)。

回过头来想想,好像是这么回事,有点强行的意思了

但是既然能把IO提高比单纯使用asyncio的8倍左右,似乎很nice很有进行实用的意义
(虽然对python web业内实际情况并没有很深的了解