为什么实习全局字符串值会导致每个多处理进程使用更少的内存?

我有一个 Python 3.6 数据处理任务,它涉及预加载一个大字典,用于按 ID 查找日期,以便在多处理模块管理的子进程池的后续步骤中使用。这个过程占用了盒子上的大部分内存,所以我应用的一项优化是“实习”存储在字典中的字符串日期。正如我预期的那样,这将 dict 的内存占用减少了几个 GB,但它也产生了另一个意想不到的效果。

在应用实习之前,子进程在执行时会逐渐消耗越来越多的内存,我认为这是由于他们不得不将 dict 从全局内存逐渐复制到子进程的单独分配内存(这是运行Linux 等受益于 fork() 的写时复制行为。即使我没有更新子进程中的字典,看起来只读访问仍然可以通过引用计数触发写时复制。

我只希望实习能减少 dict 的内存占用,但实际上它也阻止了内存使用量在子进程生命周期中逐渐增加

这是我能够构建的一个复制行为的最小示例,尽管它需要一个大文件来加载并填充 dict 以及在值中进行足够数量的重复以确保实习提供好处。

import multiprocessing
import sys

# initialise a large dict that will be visible to all processes
# that contains a lot of repeated values
global_map = dict()
with open(sys.argv[1], 'r', encoding='utf-8') as file:
  if len(sys.argv) > 2:
    print('interning is on')
  else:
    print('interning is off')
  for i, line in enumerate(file):
    if i > 30000000:
      break
    parts = line.split('|')
    if len(sys.argv) > 2:
      global_map[str(i)] = sys.intern(parts[2])
    else:
      global_map[str(i)] = parts[2]

def read_map():
  # do some nonsense processing with each value in the dict
  global global_map
  for i in range(30000000):
    x = global_map[str(i)]
  y = x + '_'
  return y

print("starting processes")
process_pool = multiprocessing.Pool(processes=10)

for _ in range(10):
  process_pool.apply_async(read_map)

process_pool.close()

process_pool.join()

我运行了这个脚本并监控htop以查看总内存使用情况。

实习? 打印“启动进程”后的内存使用情况 之后的峰值内存使用量
7.1GB 28.0GB
是的 5.5GB 5.6GB
以上是为什么实习全局字符串值会导致每个多处理进程使用更少的内存?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>