【问题标题】:ExecutorService Future::get very slowExecutorService Future::get 很慢
【发布时间】:2017-01-16 20:25:22
【问题描述】:

我正在并行化一个相当复杂的程序以使其更快。为此,我大部分时间使用ExecutorService。到目前为止,它运行得很好,但后来我注意到,仅仅一行代码就可以让我的程序运行速度减半。这是exactScore.get() 的行。

我不知道为什么,但有时需要超过 0.1 秒才能获得 Future Object 的双精度值。

这是为什么?我该如何处理它运行得更快?有没有办法在多线程时直接写在Double[]? 谢谢

int processors = Runtime.getRuntime().availableProcessors();
    ExecutorService service = Executors.newFixedThreadPool(processors);

    // initialize output
    Double[] presortedExScores = new Double[sortedHeuScores.length];

    for(int i =0; i < sortedHeuScores.length; i++ ){
        final int index = i;
        final Collection<MolecularFormula> formulas_for_exact_method = multimap.get(sortedHeuScores[i]);
        for (final MolecularFormula formula : formulas_for_exact_method){
            Future<Double> exactScore = service.submit(new Callable<Double>() {
                @Override
                public Double call() throws Exception {
                    return getScore(computeTreeExactly(computeGraph(formula)));
                }
            });
            presortedExScores[index] = exactScore.get();
        }

    }

【问题讨论】:

    标签: java multithreading performance future executorservice


    【解决方案1】:

    这是意料之中的。那不是“慢”;它只是在做它的工作。

    来自get()的javadoc:

    如有必要,等待计算完成,然后检索其结果。

    长话短说:您似乎不了解您在代码中使用的概念。 未来的想法是它在未来的某个时间点做事。

    通过调用get(),您表示:我不介意等待现在直到“未来”“背后”的计算结果可用。

    因此:您必须退后一步,再次查看您的代码;了解您的不同“活动线索”如何真正发挥作用;以及他们如何/何时重聚。

    想到的一个想法:现在,您正在循环中创建 Future 对象;在你创建了 Future 之后,直接调用 get() 就可以了。这与创建多个 Futures 的想法完全矛盾。换句话说:而不是去:

    foreach X
      create future X.i
      wait/get future X.i
    

    你可以做类似的事情

    foreach X
      create future X.i
    
    foreach X
      wait/get for future X.i
    

    换句话说:让你的未来真正并行地做事;而不是强制执行顺序处理。

    如果这没有帮助“足够”,那么正如所说:您必须查看您的整体设计,并确定是否有进一步“分开”事物的方法。现在所有活动都“紧密”地一起发生;惊喜:当你同时做很多工作时,这需要时间。但正如您可能猜到的那样:这样的重新设计可能需要做很多工作;在不了解您的问题/代码库的情况下几乎是不可能的。

    更复杂的方法是编写代码,其中每个 Future 都有一种表达“我完成了”的方式 - 然后您将“仅”启动所有 Future;并等到最后一个回来。但如前所述;我无法在这里为您设计完整的解决方案。

    这里还有一个非常重要的要点:不要只是盲目地使用一些“碰巧”可以工作的代码。编程的一个本质是理解源代码中使用的每一个概念。 运行它并发现“哦,get() 让事情变慢”之前,您应该非常清楚自己的代码在做什么。

    【讨论】:

    • 如果我不尝试在 for 循环中获取它会更好吗?因为如果我对您的理解正确,其他 Executor 在我的 exactScor.get 完成之前不会得到工作(所以这次没有新的多线程)。
    • 请看我的各种更新。它可以帮助将事情分成两个循环;但这实际上取决于超出简单 SO 问题/答案讨论的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 2021-07-11
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    相关资源
    最近更新 更多