0

我正在尝试提高应用程序中 I/O 的速度,因此我决定使用多个线程来存储它。文件在层次结构 book/symbol/file 中结构化,多个线程可能同时将多个文件保存在同一目录中。当我按顺序保存所有文件时,没有问题。但是,当多线程启动时,有时文件格式错误并且加载它会引发“IOException:无效块”。任何想法为什么在这种情况下并发可能会搞砸?

下面的代码:

    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();
        }
4

1 回答 1

1

如果您正在寻找性能,那么您几乎肯定会通过在和BufferedOutputStream之间引入一个更大的性能提升。GZIPOutputStramFileOutputStream

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


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

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

于 2013-01-04T15:48:44.753 回答