当前位置: 首页 > 知识库问答 >
问题:

ForkJoinPool相同代码不同风格的延迟不同

班昱
2023-03-14

我试图将paralleStream与自定义的ForkJoin池一起使用,该任务执行网络调用。当我使用以下样式时

pool.submit(() -> {
        ioDelays.parallelStream().forEach(n -> {
            induceRandomSleep(n);
        });
    }).get();
for (final Integer num : ioDelays) {
        ForkJoinTask<Integer> task =  pool.submit(() -> {
            return induceRandomSleep(num);
        });
        tasks.add(task);
    }
    int count = 0;
    final List<Integer> returnVals = new ArrayList<>();
    tasks.forEach(task -> {
        try {
            returnVals.add(task.get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    });

如果使用parallelStream,那么ForkJoinPool.Common是否以某种方式参与其中?下面是模拟上述两种样式的整个程序

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;

public class FJTPExperiment {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ForkJoinPool pool = new ForkJoinPool(200);

        List<Integer> ioDelays = new ArrayList<>();
        for (int i = 0; i <2000; i++) {
            ioDelays.add( (int)(300 *Math.random() + 200));
        }
        int originalCount = 0;
        for (Integer val : ioDelays) {
            originalCount += val;
        }
        System.out.println("Expected " + originalCount);
        System.out.println(Thread.currentThread().getName() + " ::::Number of threads in common pool :" + ForkJoinPool.getCommonPoolParallelism());


        long beginTimestamp = System.currentTimeMillis();
        pool.submit(() -> {
            ioDelays.parallelStream().forEach(n -> {
                induceRandomSleep(n);
            });
        }).get();
        long endTimestamp = System.currentTimeMillis();
        System.out.println("Took " + (endTimestamp - beginTimestamp) + " ms");


        List<ForkJoinTask<Integer>> tasks = new ArrayList<>();
        beginTimestamp = System.currentTimeMillis();
        for (final Integer num : ioDelays) {
            ForkJoinTask<Integer> task =  pool.submit(() -> {
                return induceRandomSleep(num);
            });
            tasks.add(task);
        }
        int count = 0;
        final List<Integer> returnVals = new ArrayList<>();
        tasks.forEach(task -> {
            try {
                returnVals.add(task.get());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        });
        endTimestamp = System.currentTimeMillis();
        for (Integer val : returnVals) {
            count += val;
        }
        System.out.println("Count " + count);
        System.out.println("Took " + (endTimestamp - beginTimestamp) + " ms");
    }


    public static int induceRandomSleep(int sleepInterval) {
        System.out.println(Thread.currentThread().getName() + " ::::sleeping for " + sleepInterval + " ms");
        try {
            Thread.sleep(sleepInterval);
            return sleepInterval;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return sleepInterval;
        }
    }
}

共有1个答案

鱼锦
2023-03-14

我最终找到了答案问题有两个部分:

1)只有一个任务被提交给ForkJoinPool,它是如何产生多个线程的?

查看JDK实现,似乎在调用parallelStream时,它会检查当前线程是否是ForkJoinWorkerThread,如果是,则任务会被推送到客户ForkJoinPool的队列中,如果不是,则会被推送到ForkJoinPool.Common。这也通过日志进行了验证。

2)如果它能工作,为什么它慢?

因为并行性不是从自定义ForkJoinPool的并行性派生的,而是从ForkJoinPool.Common的并行性派生的,后者默认情况下限制为CPU核心数-1。这里是JDK实现,leaf_target是在这里派生的。如果这必须正常工作,那么应该有一个分支,它从自定义线程池的并行性派生leaf_target

 类似资料:
  • 希望你们都平安无事 假设我有以下过程:2个不同的源,队列,延迟,和接收器。我有一个叫“病人”的探员。 我的目标:有不同的服务率(延迟时间)的病人谁是来自第一来源(使用百分比)。换句话说,我想有一个例子;10%的患者(来自源1)延迟时间等于5分钟,90%的患者延迟时间等于10分钟。 我所做的:是我为代理(病人)分配了一个名为“百分比”的参数。并使用我键入的第一个源的“On exit” 然后在延迟时间

  • 我偶然发现了一些毫无意义的东西。我有这个Python代码,它做2个简单的for循环,只是测量执行时间。然而,我发现从一个函数调用完全相同的代码需要一半的时间。有人能解释一下为什么吗? 这里是输出:

  • https://leetcode.com/problems/find-all-numbers-dispapered-in-an-array/discuss/93007/simple-java-in-place-sort-solution 你能查一下上面的链接吗? 我看不懂密码 然后,第一个只是简单地使用我们可以检查是不是值。 第二个, 它最终也是一样的东西,只是为了证明索引值=index+1。 但

  • 我正在使用Gradle构建系统在Android Studio上编写一个具有多种风格的应用程序。主应用程序/AndroidManifest文件有自己定义的启动程序活动,我想用Flavor/AndroidManifest文件覆盖它,我在其中定义了其他启动程序活动,这些活动只是Flavor/source代码的一部分。 编辑:以下是文件层次结构: 应用程序名称- src公司- 但当我这样做时,它给出了一个

  • 问题内容: 当与MySQL数据库连接时,我有几种方法可以做同样的事情,保存或加载不同类型的参数。目前,我对每种类型都有不同的方法。如何合并这些方法,以便它们支持不同的类型? 下面是两个非常相似但使用不同类型的方法的示例: 请注意,在该示例中,类型均为数字。在类型完全不同的情况下(例如int和String),如何避免使用近乎重复的方法? 问题答案: 您可以在此处应用 策略 模式。 …