Scala 并发性能问题

Scala concurrency performance issues

我有一个数据挖掘应用程序。

有 1 个 Mining Actor 接收并处理包含 1000 个对象的 Json。我把它放到一个列表中,foreach,我通过将数据发送到 1 个 Logger Actor 来记录数据,该 Logger Actor 将数据记录到许多文件中。

按顺序处理列表,我的应用程序使用 700MB 并需要大约 15 秒的 20% cpu 功率来处理(4 核 cpu)。当我并行化列表时,我的应用程序使用 2GB 和 ~ 相同的时间和 cpu 来处理。

我的问题是:

  1. 既然我并行化了列表和计算,计算时间不应该减少吗? 我认为在这种情况下只有一个 Logger Actor 是一个瓶颈。计算速度可能更快,但瓶颈隐藏了速度的提高。因此,如果我向池中添加更多记录器,应用程序时间应该会减少吗?

  2. 为什么内存会跳到2GB? JVM 是否必须将整个集合存储在内存中才能并行化?而计算完成后,JVM垃圾收集器应该如何处理呢?

没有更多细节,任何答案都是猜测。然而,即使是猜测也可能为您指明正确的方向。

  1. 并行执行应该会减少 运行 时间,但您的问题可能出在其他地方。出于某种原因,即使在单线程模式下,您的 CPU 也经常闲置。您没有指定是从磁盘还是网络读取输入,或者您将输出写入何处。您明确地说您将日志写入很多文件。磁盘和网络 reading/writing 在您的情况下可能比数据处理花费更长的时间。由于此 I/O 等待,您的进程很可能处于空闲状态。您不应该期望将 80% 的时间都花在等待 I/O 上的作业并行化会带来任何加速。因此,我也怀疑记录器不是这里的瓶颈。
  2. 如果您的线程每个分配大量内存,内存使用量可能会跳跃。在这种情况下,您拥有的线程越多,所需的内存就越多。我不知道你在并行化什么样的集合,但大多数都完全存储在内存中。是的,垃圾收集器将释放任何不需要您显式释放它们的资源,例如文件。
  1. How many threads for reading and writing to the hard disk?
  2. 内存增加是因为我发送消息的速度比 Logger 写入的速度快,因此邮箱的大小会膨胀,直到 Logger 处理完消息并且 GC 启动。

我通过将状态写入协议缓冲区文件解决了这个问题。在进行任何写入之前,我会与 protobuf 文件进行比较,因为读取比写入便宜得多。我的资源使用率现在为 10%,持续 2 秒,内存不足 400MB。