Java 使用多个线程保存多个gzip文件

Java 使用多个线程保存多个gzip文件,java,multithreading,gzip,Java,Multithreading,Gzip,我试图提高我的应用程序中I/O的速度,所以我决定使用多个线程来存储它。文件在层次结构book/symbol/file中结构化,多个线程同时将多个文件保存在同一目录中。当我按顺序保存所有文件时,没有问题。但是,当多线程启动时,有时文件格式不正确,加载它会引发“IOException:invalid block”。你知道为什么在这种情况下并发会把事情搞砸吗 代码如下: private void storeAppendingTimestamps(Series timeSeries) throw

我试图提高我的应用程序中I/O的速度,所以我决定使用多个线程来存储它。文件在层次结构book/symbol/file中结构化,多个线程同时将多个文件保存在同一目录中。当我按顺序保存所有文件时,没有问题。但是,当多线程启动时,有时文件格式不正确,加载它会引发“IOException:invalid block”。你知道为什么在这种情况下并发会把事情搞砸吗

代码如下:

    private void storeAppendingTimestamps(Series timeSeries) throws MetricPersistException {
        Metric metric = timeSeries.getMetric();
        Path outPutFile;
        try {
            outPutFile = generateOutputFilePath(metric);
            if (!Files.exists(outPutFile)) {
                createNewFile(outPutFile);
            }
        } catch (IOException e) {
            throw new PersistException("Cannot create output file for metric " + metric);
        }
        try (PrintWriter writer = new PrintWriter(new GZIPOutputStream(new FileOutputStream(outPutFile.toFile(), true)), true)) {
            for (SeriesDataPoint dataPoint : timeSeries.getTimeSeriesPoints()) {
                writer.println(String.format("%d %s", dataPoint.getTimestamp().getMillis(), formatPlain(dataPoint.getValue())));
            }
            writer.close();
        } catch (IOException e) {
            throw new MetricPersistException(String.format("IO Exception has occured while persisting metric %s: %s", metric, e.getMessage()));
        }
    }
以及分割工作的代码:

private void persistTimeSeries(Collection<Series> allSeries, CompletionService<Void> executorService) throws MetricPersistException {
        final LoggingCounter counter = new LoggingCounter(logger, "metric series file", 10000);
        for (final MetricTimeSeries series : allSeries) {
            executorService.submit(new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    persister.persistTimeSeries(series);
                    counter.increment();
                    return null;
                }
            });
        }
            for (int i = 0; i < allSeries.size(); i++) {
                Future<Void> future = executorService.take();
                future.get();
            }
            counter.finish();
        }
private void persistTimeSeries(集合allSeries,CompletionService executorService)引发MetricPersistException{
最终LoggingCounter计数器=新的LoggingCounter(记录器,“公制系列文件”,10000);
用于(最终MetricTimeSeries系列:allSeries){
executorService.submit(新的可调用(){
@凌驾
public Void call()引发异常{
persister.persistTimeSeries(系列);
counter.increment();
返回null;
}
});
}
对于(int i=0;i
如果您正在寻找性能,那么在
GZIPOutputStram
FileOutputStream
之间引入
BufferedOutputStream
,几乎肯定会获得更大的性能提升

同时,添加一个具有正确编码规范的
OutputStreamWriter
,以便不在您的特定机器上运行的人能够正确解释该文件


我看到的一段明显线程不安全的代码位于
storeAppendingTimestamps()
:如果有多个序列映射到同一个输出文件,那么它们在打开和写入同一个文件时都有竞争条件(创建文件时也有竞争条件,但我假设这是一个幂等操作)


如果可能有多个系列映射到同一文件名,那么您需要一个线程安全/种族安全防护。类似于
ConcurrentHashMap
的东西,用于存储正在处理的文件名。如果发生冲突,请退出任务(并发出警告)。

我们可以查看您的代码吗?以及完整的错误堆栈跟踪吗?您知道,新手手中的并发性几乎在所有情况下都会出错,而不仅仅是在您的情况下,对吗?此外,请检查(基准测试)它是否真的是一种优势。在今天的计算机上,您的瓶颈可能是I/O,而线程可能对此没有帮助。如果您是IO绑定的,添加线程只会使问题变得更糟。这并不能回答他的问题,因此更适合作为注释。@Gray-也许。但我觉得解决基本问题比具体实现更有用。尤其是在OP没有提供完整信息的情况下。这是如何解决您的问题@Bober02?在该级别添加缓冲区konda感觉更快。您可以简单地增加gzip流中缓冲区的大小以加快速度。它只是感觉更快,因为您延迟了io操作,并且BufferedOutputStream的默认大小比GziOutputStrem大,但是只添加缓冲区会使您很难知道实际使用了多少ram,以及何时实际写入以及使用了多少ram