【问题标题】:Parallel write to multiple files in Java在Java中并行写入多个文件
【发布时间】:2016-07-10 18:31:00
【问题描述】:

我有什么

我有很多 CSV 文件,如下所示:

Date;Something;
2014-03-31 15:00:01;xxx;
2015-02-01 13:20:01;xxx;
2014-03-03 17:00:03;xxx;
2014-03-03 17:00:04;xxx;

第二行并非错误 - 日期是“随机”的,介于 2014 年和 2016 年之间。幸运的是,大多数日期与最后两行类似。但上面的序列是真实的例子。

文件如何并行以及为什么并行?

每年有 5000 个文件。每一个都是 gzip 压缩的。所以IO不是问题。 CPU 现在很无聊。

我需要什么

上述文件中的行按天分组在单独的文件中。我不在乎里面的顺序。

我在想什么

使用 Java 并行流读取文件。但我不知道如何将线程安全写入多个文件? 我发现了类似的东西:Write to text file from multiple threads?Threads and file writing 但我不确定这是否可行?

【问题讨论】:

  • 不明白为什么要从多个线程写入单个文件。您是否需要为每个输入文件生成多个输出文件(针对每一天组)?或者您想汇总所有输入文件?
  • 我想为所有输入文件的每一天生成文件。因此,从具有混合内容的文件组中,我希望每天收到一个文件。
  • 您为什么要尝试优化性能?你有多少 TB 的数据?
  • 输入的是一个文件还是多个文件?
  • 这就是问题所在。除非您正在使用某种疯狂的算法,否则 CPU 不会成为瓶颈。因此,并行运行不会对您有所帮助。你受限于 IO。现在,如果输入像 100k 个不同的文件,并行可能会有所帮助。如果输入像 10 个文件,我认为多线程不会有任何帮助。

标签: multithreading java-8


【解决方案1】:

我的直觉是不要过度思考这些事情。我的方法是:

  1. 每个输入文件都在一个池化线程上逐行处理。当一个 遇到新日期,打开一个新的文件编写器并将其放入 地图(日期是关键)。
  2. 将您刚刚读到的一行写入相应的写入器(访问 作家,自己编写并在地图中添加一个条目必须是 当然同步)
  3. 设置屏障以在所有处理完毕后立即关闭所有输出文件 线程完成。

虽然实现和调试简单,但这种方法并非万无一失,也无法提供最佳性能。 缺点是:

  1. 写入文件的争用
  2. 关于改变文件写入者的地图的争论
  3. 用尽打开的文件描述符(我们为每个 日期)

如果性能是主要问题,我会提倡使用 map-reduce 方法,其中每个文件处理线程生成许多日期隔离文件,然后另一个进程连接这些文件。

【讨论】:

  • 如何实现“2”点?这是最大的问题:(
【解决方案2】:

有很多可能性:

  • 线程池 + IO 方法

线程池。每个线程读取一个输入文件并写入多个输出文件(取决于输出文件的数量 - 也许您可以打开所有输出文件,由于打开文件数量的限制,可能只打开部分输出文件)

  • 2x 线程池 + Map<Int, ArrayBlockingQueue> + IO 方法

用于读取文件的线程池。每个线程解析数据并将结果放入 ArrayBlockingQueue 实例中,该实例使用日期的哈希函数找到。每个 ArrayBlockingQueue 都有一个线程负责写入输出文件。

  • 单线程 + NIO 方法(非阻塞)

一个线程使用 NIO 从多个输入文件读取并写入多个输出文件。

  • 以上的混合

选择的解决方案取决于多种因素:

  • 此功能是否是您的应用程序的性能瓶颈?
  • 最简单的单线程 IO 方案是不是太慢了?
  • 您希望/可以投入多少时间
  • 您的操作系统和硬盘

【讨论】:

  • 我现在没有瓶颈 - CPU 低,IO 低。单线程太慢了,因为我可以让它并行:)。关于我不知道的最后一个问题。
  • @Piotr Stapp:这句话毫无意义。软件总是消耗所有资源,直到至少有一种资源限制它。加速操作的唯一方法是识别当前的限制资源并解除约束。
  • 100%只使用一个核心导致CPU低
猜你喜欢
  • 2014-03-15
  • 1970-01-01
  • 2021-04-02
  • 2015-08-17
  • 2018-10-19
  • 2018-12-28
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多