首页 > 解决方案 > 大内存使用会减慢不相关的代码

问题描述

我正在维护一个 Go 项目的代码,该项目读取和写入大量数据,并且已经成功完成了一段时间。最近,我做了一个更改:在程序开始时将一个包含大约 200 万条记录的 CSV 文件加载到一个带有 struct 值的映射中。此映射仅在 B 部分中使用,但首先在 A 部分中执行。第一部分的运行速度明显比以前慢(处理时间增加了四倍)。这很奇怪,因为那部分逻辑没有改变。我花了一个星期试图解释这是怎么发生的。以下是我采取的步骤(当我提到性能时,我总是指 A 部分,其中不包括将数据加载到内存中的时间,实际上与它无关):

在这里,我绘制了有和没有内存中数据的指标:在此处输入图像描述

什么可能导致这种影响或我如何找到它?

标签: performancegomemory

解决方案


所以如果我做对了,你的流程看起来像这样:

  1. 将 200 万行从 CSV 读入 map -> struct
  2. 运行 A 部分(不需要来自 CSV 的数据)
  3. 使用 CSV 中的数据运行 B 部分

为什么要在需要之前读取数据,这是第一个问题,但这可能不是重点。

实际上,垃圾收集器通常会访问映射中的 200 万个结构。根据所GOGC具有的值,垃圾收集器的起搏器组件可能会随着分配的内存量的增加而更频繁地启动。因为这个映射是留给以后使用的,所以 GC 没有什么可做的,但无论如何它都会占用检查数据的周期。您可以做很多事情来验证并解释这种行为 - 所有这些事情都应该可以帮助您排除/确认垃圾收集是否会减慢您的速度。

  • 分析代码(显然,对诊断很重要)IIRC,CPU 配置文件更容易显示 GC 干预
  • 尝试禁用垃圾收集 ( debug.SetGCPercent(-1))
  • 将地图存储在sync.Pool. 这是一种为您设计的类型,用于保留您将手动管理的内容,并移出常规 GC 周期。
  • 仅在需要时阅读 CSV,不要在“A 部分”之前阅读
  • 流式传输文件,而不是在大量地图中读取它。200万行,在内存中读取所有这些而不是逐行读取有什么价值?

推荐阅读