Python 我试图了解如何通过多处理共享只读对象

Python 我试图了解如何通过多处理共享只读对象,python,python-2.7,shared-memory,python-multiprocessing,copy-on-write,Python,Python 2.7,Shared Memory,Python Multiprocessing,Copy On Write,我试图了解如何通过多处理共享只读对象。当它是全局变量时,共享bigset可以正常工作: from multiprocessing import Pool bigset = set(xrange(pow(10, 7))) def worker(x): return x in bigset def main(): pool = Pool(5) print all(pool.imap(worker, xrange(pow(10, 6)))) pool.close() pool

我试图了解如何通过多处理共享只读对象。当它是全局变量时,共享
bigset
可以正常工作:

from multiprocessing import Pool

bigset = set(xrange(pow(10, 7)))

def worker(x):
  return x in bigset

def main():
  pool = Pool(5)
  print all(pool.imap(worker, xrange(pow(10, 6))))
  pool.close()
  pool.join()

if __name__ == '__main__':
  main()
htop
显示父进程使用100%的CPU和0.8%的内存,而工作负载在五个子进程之间均匀分布:每个子进程使用10%的CPU和0.8%的内存。一切都很好

但是如果我把
bigset
移到
main
里面,数字就开始疯狂了:

from multiprocessing import Pool
from functools import partial    

def worker(x, l):
  return x in l

def main():
  bigset = set(xrange(pow(10, 7)))
  _worker = partial(worker, l=bigset)
  pool = Pool(5)
  print all(pool.imap(_worker, xrange(pow(10, 6))))
  pool.close()
  pool.join()

if __name__ == '__main__':
  main()
现在
htop
显示2或3个进程在50%到80%的CPU之间上下跳跃,而其余进程使用的CPU不到10%。虽然父进程仍然使用0.8%的内存,但现在所有子进程都使用1.9%的内存


发生了什么?

当您将
bigset
作为参数传递时,它会被父进程pickle,并被子进程取消pickle。[1][2]

酸洗和拆开一大套需要很多时间。这就解释了为什么很少有进程在执行它们的工作:父进程必须pickle很多大对象,子进程必须等待。父进程是一个瓶颈

酸洗参数意味着必须将参数发送到进程。从一个进程向另一个进程发送数据需要系统调用,这就是为什么用户空间代码没有看到100%的CPU使用率。部分CPU时间花在内核空间上。[3]

酸洗对象并将其发送到子流程也意味着:1。需要为pickle缓冲区提供内存;2.每个子流程都获得一个
bigset
的副本。这就是为什么您会看到内存使用量的增加

相反,当
bigset
是一个全局变量时,它不会发送到任何地方(除非您使用的是非fork变量)。它就像子进程一样被继承,使用
fork()
的常规写时复制规则


脚注:

  • 如果您不知道“pickle”是什么意思:它是标准Python协议之一,用于将任意Python对象转换为字节序列或从字节序列转换为字节序列

  • imap()
    &co.在后台使用,队列通过酸洗/解酸洗对象来工作

  • 我尝试运行您的代码(使用
    all(pool.imap(_worker,xrange(100)))
    以加快进程),结果得到:用户时间2分钟,系统时间13秒。这几乎是10%的系统时间