ForkJoinPool:invokeAll() 方法的加入顺序错误吗?

huangapple 未分类评论50阅读模式
英文:

ForkJoinPool: does invokeall() join in the wrong order?

问题

据我所了解,ForkJoinPool使用“后进先出原则(LiFo)”。也许我能找到的最好解释是这个链接。然而,ForkJoinPool.java中的invokeall()方法似乎以任务提交的顺序(FiFo)加入(是quietlyjoin()吗?),请参见下面的代码。这样做难道不是更有意义的吗,因为所有处理都是LiFo吗?

这样做是否会减少“补偿线程”?我考虑重新编写我的代码,以LiFo的方式提交任务,而不是使用invokeall(),并在此基础上加入它们。另请参见:

ForkJoinPool在invokeAll/join期间停顿

ForkJoinPool似乎浪费了一个线程

编辑:将任务提交到工作程序的外部队列或双端队列会有所区别。我指的是工作程序的双端队列。我认为invokeall()在这里可能会导致线程停顿。

public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
        // 在此类的以前版本中,该方法构造了一个任务来运行ForkJoinTask.invokeAll,但现在外部调用多个任务至少同样高效。
        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());

        try {
            for (Callable<T> t : tasks) {
                ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
                futures.add(f);
                externalSubmit(f);
            }
            for (int i = 0, size = futures.size(); i < size; i++)
                ((ForkJoinTask<?>) futures.get(i)).quietlyJoin();
            return futures;
        } catch (Throwable t) {
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(false);
            throw t;
        }
    }
英文:

As far as I understand, a ForkJoinPool uses the 'Last-in-First-Out principle (LiFo)'. Perhaps the best explanation I could find is this link. However, the invokeall() method in ForkJoinPool.java seems to join (quietlyjoin() ?) the tasks in the order where they were submitted (FiFo), see the code below. Doesn't it make more sense to do it the other way around since all processing is LiFo?

Wouldn't this lead to fewer 'compensation threads' ? I am thinking of rewriting my code to submit tasks, rather than using invokeall(), and join them on the LiFo basis because of this. See also:

ForkJoinPool stalls during invokeAll/join

ForkJoinPool seems to waste a thread

EDIT: there is a difference whether a task is submitted to the external que or the deque of a worker. I am refering to the deque of the worker. I assume that invokeall() can lead to threadstalling here.

public &lt;T&gt; List&lt;Future&lt;T&gt;&gt; invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks) {
        // In previous versions of this class, this method constructed
        // a task to run ForkJoinTask.invokeAll, but now external
        // invocation of multiple tasks is at least as efficient.
        ArrayList&lt;Future&lt;T&gt;&gt; futures = new ArrayList&lt;&gt;(tasks.size());

        try {
            for (Callable&lt;T&gt; t : tasks) {
                ForkJoinTask&lt;T&gt; f = new ForkJoinTask.AdaptedCallable&lt;T&gt;(t);
                futures.add(f);
                externalSubmit(f);
            }
            for (int i = 0, size = futures.size(); i &lt; size; i++)
                ((ForkJoinTask&lt;?&gt;)futures.get(i)).quietlyJoin();
            return futures;
        } catch (Throwable t) {
            for (int i = 0, size = futures.size(); i &lt; size; i++)
                futures.get(i).cancel(false);
            throw t;
        }
    }

huangapple
  • 本文由 发表于 2020年4月6日 16:00:26
  • 转载请务必保留本文链接:https://java.coder-hub.com/61055339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定