[英]java 8 parallel stream takes more time
我正在尝试了解java 8并行流。 我写了下面的代码,首先使用Executor,然后使用并行流。 看起来平行流需要两倍(10秒)的时间与Executor接近(5秒)。 在我看来,并行流也应该表现出类似的性能。 任何想法为什么并行流需要两倍的时间? 我的电脑有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,您会注意到类似的性能。
当然,无法保证此代码在不同环境中的行为相同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.