我使用此script(请参阅最后的代码)来评估在父进程派生时是共享还是复制了全局对象.简要地说,脚本创建了一个全局数据对象,并且子进程对数据进行迭代.该脚本还监视内存使用情况,以评估对象是否在子进程中被复制.结果...

我使用此script(请参阅最后的代码)来评估在父进程派生时是共享还是复制了全局对象.
简要地说,脚本创建了一个全局数据对象,并且子进程对数据进行迭代.该脚本还监视内存使用情况,以评估对象是否在子进程中被复制.
结果如下:
>数据= np.ones((N,N)).在子进程中的操作:
data.sum().结果:数据共享(无副本)
> data = list(range(pow(10,8))).子进程中的操作:sum(data).结果:数据被复制.
> data = list(range(pow(10,8))).子进程中的操作:对于数据中的x:通过.结果:数据被复制.
由于写时复制,因此预期结果1).我对结果2)和3)感到有些困惑.为什么要复制数据?
脚本
source
import multiprocessing as mp
import numpy as np
import logging
import os
logger = mp.log_to_stderr(logging.WARNING)
def free_memory():
total = 0
with open('/proc/meminfo', 'r') as f:
for line in f:
line = line.strip()
if any(line.startswith(field) for field in ('MemFree', 'Buffers', 'Cached')):
field, amount, unit = line.split()
amount = int(amount)
if unit != 'kB':
raise ValueError(
'Unknown unit {u!r} in /proc/meminfo'.format(u = unit))
total += amount
return total
def worker(i):
x = data.sum() # Exercise access to data
logger.warn('Free memory: {m}'.format(m = free_memory()))
def main():
procs = [mp.Process(target = worker, args = (i, )) for i in range(4)]
for proc in procs:
proc.start()
for proc in procs:
proc.join()
logger.warn('Initial free: {m}'.format(m = free_memory()))
N = 15000
data = np.ones((N,N))
logger.warn('After allocating data: {m}'.format(m = free_memory()))
if __name__ == '__main__':
main()
详细结果
运行1个输出
[WARNING / MainProcess]初始免费:25.1 GB
[WARNING / MainProcess]分配数据后:23.3 GB
[WARNING / Process-2]可用内存:23.3 GB
[WARNING / Process-4]可用内存:23.3 GB
[WARNING / Process-1]可用内存:23.3 GB
[WARNING / Process-3]可用内存:23.3 GB
运行2输出
[WARNING / MainProcess]初始免费:25.1 GB
[WARNING / MainProcess]分配数据后:21.9 GB
[WARNING / Process-2]可用内存:12.6 GB
[WARNING / Process-4]可用内存:12.7 GB
[WARNING / Process-1]可用内存:16.3 GB
[WARNING / Process-3]可用内存:17.1 GB
运行3输出
[WARNING / MainProcess]初始免费:25.1 GB
[WARNING / MainProcess]分配数据后:21.9 GB
[WARNING / Process-2]可用内存:12.6 GB
[WARNING / Process-4]可用内存:13.1 GB
[WARNING / Process-1]可用内存:14.6 GB
[WARNING / Process-3]可用内存:19.3 GB
解决方法:
它们都是写时复制.您所缺少的是,当您这样做时,例如
for x in data:
pass
由于x依次绑定到每个对象,因此数据中包含的每个对象的引用计数都会暂时增加1.对于int对象,CPython中的refcount是基本对象布局的一部分,因此将复制该对象(您确实对其进行了更改,因为refcount发生了变化).
要使之更类似于numpy.ones的情况,请尝试例如
data = [1] * 10**8
然后,只有一个唯一的对象被列表引用了很多(10 ** 8)次,因此几乎没有要复制的内容(同一对象的refcount会增加和减少很多次).
本文标题为:python-多重处理:为什么在复制列表时与子进程共享一个numpy数组?


基础教程推荐
- Python入门教程之三元运算符的使用详解 2022-10-20
- Ubuntu16.04切换python3和python2 2023-09-04
- centos6,python3,通过pip安装pycurl出现报错提示 2023-09-04
- Python办公自动化之Excel介绍 2023-08-09
- Python 多线程爬取案例 2022-08-30
- linux-Centos7安装python3并与python2共存 2023-09-04
- python-pycurl失败,但是curl(来自bash)在ubuntu中工作 2023-11-10
- python-“陈旧文件句柄”错误,当进程尝试读取文件时,该其他进程已被删除 2023-11-11
- 基于Python创建语音识别控制系统 2023-08-11
- 利用Python写一场新年烟花秀 2023-08-08