有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

并发Java 8并行流似乎并没有实际并行工作

我试图使用Java8的parallelStream()并行执行几个长时间运行的请求(例如web请求)。简化示例:

List<Supplier<Result>> myFunctions = Arrays.asList(() -> doWebRequest(), ...)

List<Result> results = myFunctions.parallelStream().map(function -> function.get()).collect(...

因此,如果有两个函数分别阻塞2秒和3秒,我希望在3秒后得到结果。然而,这真的需要5秒钟——也就是说,函数似乎是按顺序执行的,而不是并行执行的。我做错什么了吗

编辑:这是一个例子。当我希望它为~2000时,所用的时间为~4000毫秒

    long start = System.currentTimeMillis();

    Map<String, Supplier<String>> input = new HashMap<String, Supplier<String>>();

    input.put("1", () -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "a";
    });

    input.put("2", () -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "b";
    });

    Map<String, String> results = input.keySet().parallelStream().collect(Collectors.toConcurrentMap(
            key -> key,
            key -> {
                return input.get(key).get();
            }));

    System.out.println("Time: " + (System.currentTimeMillis() - start));

}

如果迭代entrySet()而不是keySet(),则没有任何区别

编辑:将平行零件更改为以下内容也无济于事:

 Map<String, String> results = input.entrySet().parallelStream().map(entry -> {
            return new ImmutablePair<String, String>(entry.getKey(), entry.getValue().get());
    }).collect(Collectors.toConcurrentMap(Pair::getLeft, Pair::getRight));

共 (1) 个答案

  1. # 1 楼答案

    并行执行时,分解输入集、创建任务以表示计算的不同部分、跨线程分配操作、等待结果、合并结果等都会产生开销。这超出了实际解决问题的工作。如果并行框架总是将问题分解为一个元素的粒度,那么对于大多数问题,这些开销将压倒实际计算,并行将导致执行速度变慢。因此,并行框架有一定的自由度来决定如何精细地分解输入,这就是这里发生的事情

    在您的情况下,您的输入集太小,无法分解。因此库选择按顺序执行

    在你的四核系统上试试这个:比较

    IntStream.range(0, 100_000).sum()
    

    vs

    IntStream.range(0, 100_000).parallel().sum()
    

    在这里,您为它提供了足够的输入,它将有信心通过并行执行获得成功。如果您使用负责任的测量方法(例如,JMH microbenchmark线束)进行测量,您可能会看到这两个示例之间几乎呈线性加速