以下是我将类型为ConcurrentMap<String, List<String>>
写入文件的类。地图中的关键字是路径,地图中的值将按顺序写入文件。这Task<Void>
被调用每一次有1000个值地图:Java多重打开和关闭写入文件
public class MapWriter extends Task<Void> {
private final ParsingProducerConsumerContext context;
public MapWriter(ParsingProducerConsumerContext context) {
this.context = context;
}
@Override
protected Void call() throws Exception {
if (!isCancelled() || !context.isEmpty()) {
ConcurrentMap<String, List<String>> jsonObjectMap = context.fetchAndReset();
jsonObjectMap.entrySet().forEach((t) -> {
try {
FileUtils.writeLines(new File(context.getPath() + t.getKey() + "\\sorted.json"), t.getValue(), true);
} catch (IOException ex) {
context.getLogger().log("Error writing to disk:");
context.getLogger().log(ex.toString());
context.stopEverything();
}
});
context.getLogger().log(jsonObjectMap.values().stream().mapToInt(List::size).sum() + " schedules written to disk ");
} else {
context.getLogger().log("Nothing to write");
}
return null;
}
}
所有这些任务运行的同时,有一个制片人Task
逐行读取〜2GByte文件中的行,它获取由消费者和处理放入ConcurrentMap<String, List<String>>
。
虽然这可行,但它非常缓慢!
我的研究表明,重复打开和关闭文件会产生足够的开销,从而影响性能,所以想知道以下方法是否会更好?
维护一个Map<String, File>
File
对象是开放的。 如果ConcurrentMap<String, List<String>>
中的键对应于一个打开的文件,请使用该File
参考编写 当所有处理完成后,循环使用Map<String, File>
值并关闭每个文件。
这听起来是一个明智的方式吗?将会有大约100个文件被打开。
编辑::我做了一个简单的基准使用System.nanoTime()
。生产者逐行导入的文件约为2GB,每行在6kb到10kb之间(在List<String>
中)。
此外,遇到OutOfMemory错误!我猜是因为2GByte被有效地加载到内存中,而不是写得很快?
514 jsonObjects written to disk in 2258007ms 538 jsonObjects written to disk in 2525166ms 1372 jsonObjects written to disk in 169959ms 1690 jsonObjects written to disk in 720824ms 9079 jsonObjects written to disk in 5221168ms 22552 jsonObjects written to disk in 6943207ms 13392 jsonObjects written to disk in 6475639ms 0 jsonObjects written to disk in 6ms 0 jsonObjects written to disk in 5ms 0 jsonObjects written to disk in 5ms 40 jsonObjects written to disk in 23108ms 631 jsonObjects written to disk in 200269ms 3883 jsonObjects written to disk in 2054177ms Producer failed with java.lang.OutOfMemoryError: GC overhead limit exceeded
为了完整起见,这里是制作类:
public class NRODJsonProducer extends Task<Void> {
private final ParsingProducerConsumerContext context;
public NRODJsonProducer(ParsingProducerConsumerContext context) {
this.context = context;
}
@Override
protected Void call() throws Exception {
context.getLogger().log("Producer created");
LineIterator li = FileUtils.lineIterator(new File(context.getPath() + context.getFilterFile()));
while (li.hasNext()) {
try {
context.getQueue().put(li.next());
} catch (InterruptedException ex) {
Logger.getLogger(NRODJsonProducer.class.getName()).log(Level.SEVERE, null, ex);
}
}
LineIterator.closeQuietly(li);
context.getLogger().log("Producer finished...");
return null;
}
}
给它一个去吧,让我们知道吗? –