我试图了解如何与多处理共享只读对象
I am trying to understand how to share read-only objects with multiprocessing
我正在尝试了解如何与多处理共享只读对象。共享 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,而其余进程使用不到 10% CPU。虽然父进程仍然使用 0.8% 的内存,但现在所有子进程都使用 1.9% 的内存。
发生了什么事?
当您将 bigset
作为参数传递时,它由父进程 pickle 并由子进程 unplickled。[1][2]
对大型集合进行 pickling 和 unpickling 需要很多时间。这就解释了为什么你看到很少有进程在做他们的工作:父进程必须 pickle 很多大对象,而子进程必须等待它。父进程是一个瓶颈。
Pickling 参数意味着必须将参数发送到进程。从一个进程向另一个进程发送数据需要系统调用,这就是为什么您没有看到用户 space 代码使用 100% CPU 的原因。部分 CPU 时间花费在内核上 space.[3]
腌制对象并将它们发送到子进程也意味着:1.你需要内存来存放腌制缓冲区; 2. 每个子进程得到一份bigset
。这就是您看到内存使用量增加的原因。
相反,当 bigset
是一个全局变量时,它不会被发送到任何地方(除非您使用 fork 以外的 start method。它只是由子进程继承 as-is,使用 fork()
.
的通常 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.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,而其余进程使用不到 10% CPU。虽然父进程仍然使用 0.8% 的内存,但现在所有子进程都使用 1.9% 的内存。
发生了什么事?
当您将 bigset
作为参数传递时,它由父进程 pickle 并由子进程 unplickled。[1][2]
对大型集合进行 pickling 和 unpickling 需要很多时间。这就解释了为什么你看到很少有进程在做他们的工作:父进程必须 pickle 很多大对象,而子进程必须等待它。父进程是一个瓶颈。
Pickling 参数意味着必须将参数发送到进程。从一个进程向另一个进程发送数据需要系统调用,这就是为什么您没有看到用户 space 代码使用 100% CPU 的原因。部分 CPU 时间花费在内核上 space.[3]
腌制对象并将它们发送到子进程也意味着:1.你需要内存来存放腌制缓冲区; 2. 每个子进程得到一份bigset
。这就是您看到内存使用量增加的原因。
相反,当 bigset
是一个全局变量时,它不会被发送到任何地方(除非您使用 fork 以外的 start method。它只是由子进程继承 as-is,使用 fork()
.
脚注: