我有一个Java应用程序,该应用程序当前在循环中逐行分析输入文件,并且每一行(通过特定的API)在输出文件中写入一行。
所写的行的顺序是关键(带有时间戳的行)。鉴于此,我选择了在主线程中执行整个任务,但是性能却很糟糕:我不知道有其他方法可以最大化性能,而不会利用多线程,但是由于顺序关键性我认为没有机会雇用它。顺便说一句,我不是并行执行专家,也许我不知道有没有办法使用它:是这样吗?
P.S。:( 75%的时间都花在写操作上,因此瓶颈不在文件解析中)
P.P.S:应用程序必须在本地计算机上运行。
答案 0 :(得分:2)
如果您发现执行过程中花费的时间最多是写输出,那么这已经很好地表明了速度获得最大收益的地方。在尝试优化之前,您已经正确地进行了测量。
第一步是确保FileWriter
(或FileOutputStream
,无论使用哪个)包装在BufferedWriter
或BufferedOutputStream
中,并具有足够大的缓冲区。这样,Java可以将输出放置在缓冲区中,并且仅在输出填满时才将其刷新到文件中。输出量没有变化,但是分配给了更少的I / O调用。
如果这样做不行,请查看有关java.nio
包中的类的用法的教程。 Java SE 7中添加了Java 1.4中引入的该API和提供文件系统功能的名为NIO.2的扩展。这些API提供了非阻塞I / O。非阻塞I / O背后的思想是,线程倾向于在传统I / O操作中花费大量时间,等待底层OS和硬件完成读写操作,同时不执行任何有用的工作。使用非阻塞I / O,您可以将输出放置到缓冲区中,并以异步方式将其写出,这意味着write调用会立即返回,并且可以在系统调用完成传输时继续执行其他有用的工作。这与常规的BufferedWriter或BufferedOutputStream不同,后者提供了内存中的缓冲区,但一旦刷新缓冲区,仍会阻止将其写出。
使用非阻塞I / O,您的应用程序可以在写入输出时从输入和/或过程中获取更多数据,从而更好地进行并行处理。但是,如果输出端存在很大的瓶颈,以至于读取和处理总是随着写入而“赶上”,从而淹没了输出通道的缓冲区,那么输出仍将是限制因素。毕竟,最后所有输出都必须写入文件。
一种用于执行并行输出同时仍确保输出保持可预测顺序的方法是使用内存映射文件。为此,您可以使用java.io.RandomAccessFile
,也可以将其与java.nio结合使用以进行异步编写。然后,您可以并行写入文件的不同部分。此处的缺点是,对于输出的每个部分,您都需要确保其具有特定的长度。除了某些非常特定的用例(如定长文本或某些二进制格式)外,通常情况并非如此。
最后,并行处理输入,然后确保不管输入的哪个部分首先被处理,仍要以正确的顺序写出输入是可行的。您只需要在输出中加入一些元数据(例如,通过将其包装在一些帮助器类中)来标识顺序,并让输出不写乱序。某些库可能提供有用的东西,但是带有对象的优先级队列可以包装输出并具有序列号就足够了。这是一种称为resequencer in integration patterns的模式。