【发布时间】:2016-03-26 14:55:53
【问题描述】:
问题描述如下:
我在一个目录中有大量的小日志文件,假设:
- 所有文件都遵循命名约定:
yyyy-mm-dd.log,例如:2013-01-01.log、2013-01-02.log。 - 大约有 1,000,000 个小文件。
- 所有文件的总大小为几 TB。
现在我必须为每个文件中的每一行添加一个行号,并且行号是累积的,分布在文件夹中的所有文件(文件按时间戳排序)中。例如:
- 2013-01-01.log,行号1~2500
- 在2013-01-02.log中,行号从2501~7802
- ...
- 在2016-03-26.log,行号从1590321~3280165
所有文件都被覆盖以包含行号。
约束是:
- 存储设备是 SSD,可以同时处理多个 IO 请求。
- CPU 足够强大。
- 您可以使用的总内存为 100MB。
- 尝试最大化应用程序的性能。
- 用 Java 实现和测试。
经过思考和搜索,这是我想到的最好的solution。 The code有点 很长,所以我只是对每个步骤进行简要说明:
并发统计每个文件的行数,并将映射保存到
ConcurrentSkipListMap,key为文件名,value为文件行数,key为有序。通过遍历
ConcurrentSkipListMap统计每个文件的起始行号,例如2013-01-01.log的起始行号和行数分别为1和1500,那么起始行号2013-01-02.log 是 1501。将行号添加到每个文件的每一行:使用
BufferedReader逐行读取每个文件,添加行号然后使用BufferedWriter写入相应的tmp文件。创建线程池,并发处理。同时使用线程池将所有 tmp 文件重命名为原始名称。
我已经在我的 MBP 上测试了该程序,步骤 1 和步骤 3 是预期的瓶颈。 您有更好的解决方案,还是对我的解决方案进行了一些优化?提前致谢!
【问题讨论】:
-
由于 100MB 的限制和 1M 的文件,第 34 行很可能已经在
logPath.toFile().listFiles();被炸毁。 100 MB 意味着如果您敢于将所有文件的信息同时保存在内存中,那么每个文件只有 100 个字节可供使用。 -
@Harald,谢谢。也许
logPath.toFile().list()消耗更少的内存。此外,有人建议 Java 7 中的Files.walkFileTree可能有效。我会尝试这两个,但问题是我无法创建这么多的测试日志。
标签: java multithreading java.util.concurrent