【问题标题】:Extra bytes appearing when building file data using multiple threads使用多线程构建文件数据时出现额外字节
【发布时间】:2011-04-06 00:16:24
【问题描述】:

我正在处理一个大型数据集,在构建模型后,我使用多线程(Java 中的整个项目),如下所示:

OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));

int i=0;
Collection<Track1Callable> callables = new ArrayList<Track1Callable>();

// For each entry in the test file, do watever needs to be done.
// Track1Callable actually processes that entry and returns a double value.
for (Pair<PreferenceArray, long[]> tests : new DataFileIterable(
        KDDCupDataModel.getTestFile(dataFileDirectory))) {
    PreferenceArray userTest = tests.getFirst();
    callables.add(new Track1Callable(recommender, userTest));
    i++;
}

ExecutorService executor = Executors.newFixedThreadPool(cores); //24 cores
List<Future<byte[]>> results = executor.invokeAll(callables);
executor.shutdown();

for (Future<byte[]> result : results) {
    for (byte estimate : result.get()) {
        out.write(estimate);
    }
}
out.flush();
out.close();

当我收到每个可调用的结果时,将其输出到文件中。此输出是否与初始 Callables 列表的生成顺序完全相同?尽管有些人先于其他人完成?似乎应该但不确定。

另外,我预计总共有 620 万字节将写入输出文件。但我得到了额外的 2000 字节(是的,免费)。这弄乱了我的提交,我认为这是因为一些并发问题。我在小型数据集上对此进行了测试,它似乎在那里工作正常(预期和接收到 264 个字节)。

我在 Executor 框架或 Futures 上做错了什么?

【问题讨论】:

  • 应该没什么区别,但是你可以写一个byte[]而不用遍历它的所有字节:out.write(result.get(), 0, result.get().length)
  • 如果您之前知道每个结果的大小(例如,如果它始终相同),您可以添加一个测试来检查。只是为了确保您的其他代码返回大小错误的结果没有问题。

标签: java multithreading executorservice callable


【解决方案1】:

问:顺序是否与为任务指定的顺序相同? 是的

来自 API:

返回:期货列表 代表任务,同样 由产生的顺序顺序 给定任务列表的迭代器。如果 操作没有超时,每个 任务将完成。如果确实如此 超时,其中一些任务不会 已完成。

至于“额外”字节:您是否尝试过按顺序执行所有这些操作(即,不使用执行程序)并检查是否获得不同的结果?看来您的问题不在提供的代码范围内(可能不是由于并发)。

【讨论】:

  • 非常感谢。我实际上已经尝试过顺序版本,效果很好。没有问题,除了运行大约需要 5 天。这是我从那以后所做的唯一改变。
  • 这很奇怪。您确定所有这些 Callable 都不会干扰任何其他(即它们同意获取资源)吗?
  • 没错。他们不。他们只对独立用户工作,没有共享资源。 Okie Recommender 模型实际上是一个共享资源,但它只是用于获取对 {user-item} 对的偏好。只读。更重要的是,它被记录为线程安全的。
【解决方案2】:

可调用对象的执行顺序与您在此处的代码无关。您按照将期货存储在列表中的顺序编写结果。即使它们以相反的顺序执行,文件应该看起来与您的文件写入是单线程的一样。

我怀疑您的可调用对象正在相互交互,并且根据您使用的核心数量,您会得到不同的结果。例如您可能正在使用 SimpleDateFormat。

我建议你在同一个程序中运行两次,数据集在短时间内完成。首先在线程池中仅使用一个线程运行它,第二次使用 24 个线程运行它 您应该能够将两次运行的结果与Arrays.equals(byte[], byte[]) 进行比较,并看到您得到完全相同的结果。

【讨论】:

    猜你喜欢
    • 2022-11-28
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 2021-03-16
    相关资源
    最近更新 更多