gpt4 book ai didi

java 8并行流需要更多时间

转载 作者:搜寻专家 更新时间:2023-11-01 02:20:53 25 4
gpt4 key购买 nike

我正在尝试了解 Java 8 并行流。我写了下面的代码,首先使用 Executor 然后使用并行流。似乎并行流花费的时间是 Executor 方法(5 秒)的两倍(10 秒)。在我看来,并行流也应该表现出类似的性能。知道为什么并行流需要双倍时间吗?我的电脑有 8 个内核。

/**
*
*/
package com.shashank.java8.parallel_stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
* @author pooja
*
*/
public class Sample {

public static int processUrl(String url) {

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Running Thread " + Thread.currentThread());
return url.length();
}

/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
usingExecutor();
usingParallelStream();
}

public static void usingParallelStream() {

Date start = new Date();
// TODO Auto-generated method stub
int total = buildUrlsList().parallelStream().mapToInt(Sample::processUrl).reduce(0, Integer::sum);
Date end = new Date();
System.out.println(total);
System.out.println((end.getTime() - start.getTime()) / 1000);

}

public static void usingExecutor() throws Exception {
Date start = new Date();
ExecutorService executorService = Executors.newFixedThreadPool(100);
List<Future> futures = new ArrayList<>();

for (String url : buildUrlsList()) {
futures.add(executorService.submit(() -> processUrl(url)));

}

// iterate through the future
int total = 0;
for (Future<Integer> future : futures) {
total += future.get();
}
System.out.println(total);
Date end = new Date();
System.out.println((end.getTime() - start.getTime()) / 1000);

}

public static List<String> buildUrlsList() {
return Arrays.asList("url1", "url2", "url3", "url4", "url5", "url6", "url7", "url8", "url9");

}

}

最佳答案

解释很简单。您有 8 个核心,因此 parallelStream() 通常可以将工作并行化为 8 个线程。他们都立即捕获了一个任务,然后都睡了 5 秒钟。然后其中一个接受下一个(第 9 个)任务,它再睡 5 秒。然后处理完成。这意味着总共 ~ 5 秒(8 个线程)+ 5 秒(1 个线程)= 10 秒。但是,让我们看看实际情况。我将稍微修改您的代码:

 public static int processUrl(String url) {

try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("T[" + Thread.currentThread().getId() + "] finished @[" + System.currentTimeMillis() / 1000 + "]");
return url.length();
}

使用并行流,您可能会得到类似于以下的输出:

T[1] finished @[1494267500]
T[12] finished @[1494267500]
T[17] finished @[1494267500]
T[13] finished @[1494267500]
T[14] finished @[1494267500]
T[16] finished @[1494267500]
T[11] finished @[1494267500]
T[15] finished @[1494267500]
T[12] finished @[1494267505]
36
10

请注意,同一个线程 T[12] 完成了两次任务,并在 8 个任务的第一“轮”后 5 秒完成。

您已经使用线程执行器创建了 100 个线程。所以9个线程各抢一个任务,执行时间大概5秒,因为线程池不会耗尽:

T[14] finished @[1494267783]
T[11] finished @[1494267783]
T[19] finished @[1494267783]
T[17] finished @[1494267783]
T[12] finished @[1494267783]
T[16] finished @[1494267783]
T[13] finished @[1494267783]
T[15] finished @[1494267783]
T[18] finished @[1494267783]
36
5

请注意,此处没有具有相同 ID 的线程。 (这不是为固定池选择通用线程数的建议:-)我只是在详细说明您的实际问题)。

使用调度程序进行试验并仅分配 8 个线程:

ExecutorService executorService = Executors.newFixedThreadPool(8);

然后执行时间可能大致相同,因为线程池将被耗尽。如果 URL-s 只是 8 个而不是 9 个,您会注意到类似的性能。

当然无法保证此代码在不同环境中的行为相同。

关于java 8并行流需要更多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43853518/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com