import java.util.ArrayList;
import java.util.List;
public class HowFastMulticoreProgramming {
public static void main(String[] args) {
//Produce Date
List<String> data=new ArrayList<String>();
for(int i=0;i<10000;i++){
data.add(""+i);
}
/*Style Java 1.4*/
long beforeStartJDK14=System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
System.out.println(data.get(i));
}
long afterPrintJDK14=System.currentTimeMillis();
/*Style Java 1.5*/
long beforeStartJDK15=System.currentTimeMillis();
for (String s : data) {
System.out.println(s);
}
long afterPrintJDK15=System.currentTimeMillis();
long beforeStartJDK18=System.currentTimeMillis();
data.parallelStream().forEach(string-> System.out.println(string));
long afterPrintJDK18=System.currentTimeMillis();
System.out.println("Milis Need JDK 1.4 : "+(afterPrintJDK14-beforeStartJDK14));
System.out.println("Milis Need JDK 1.5 : "+(afterPrintJDK15-beforeStartJDK15));
System.out.println("Milis Need JDK 1.8 : "+(afterPrintJDK18-beforeStartJDK18));
}
}
我有3种样式可以打印List(基于JDK版本)。但每种风格都需要时间来完成。实际上风格jdk 8与lambdas ..任何风格都需要更大。 怎么来的?
这是我运行此代码所得到的; 时间Milis需要JDK 1.4:85 时间Milis需要JDK 1.5:76 时间Milis需要JDK 1.8:939
我希望有人能回答这个问题。
答案 0 :(得分:4)
这种比较完全没有意义。
首先,前两个变体完全由I / O时间控制。任何输出的任何循环通常都是。迭代的方式可能会产生噪音。 I / O很慢。
但它并不像你在第三个版本中做的那么慢。在第三个变体中,使用parallelStream()
,它调用Java8的join / fork机制。您正在生成多个线程(可能与您拥有CPU核心数一样多)。您正在分配任务以在这些线程上编写列表元素。然后,您将从每个线程写入相同的流,序列化其操作,即在您完成创建线程和分发任务的所有工作之后,你现在仍然只做一件事,加上你现在也会产生大量的同步开销。
如果你想做一个有趣的比较,你需要将数据转换成其他一些数据,你需要对每个项目进行非平凡(但不是同步)的工作,这样任务管理开销就不会淹没计算时间。
在此期间,请尝试使用stream()
代替parallelStream()
。这应该将时间缩短到大致相当于其他两个变体的时间。但这并没有使它更有意义。
答案 1 :(得分:1)
免责声明:您正在进行微基准测试和微基准测试are hard to do。我确信下面稍微改变的代码本身就有足够的问题。
parallelStream()
需要一些启动时间,并且您有多个Thread
带来的开销。
另一个问题是,你正在为每个项目做System.out.println()
- 它是IO,所以除了迭代之外你还要测量很多。当您从多个线程访问一个流(System.out
)时,这尤其是一个问题。
如果你删除你的打印语句,JVM可能只是跳过循环,这就是为什么我只是将每个元素添加到一个总和。应该非常快,并且不会被优化掉。
当运行以下示例,列表大小为100000000(创建大约需要一分钟)时,我得到以下结果:
Milis Need JDK 1.4 : 190
Milis Need JDK 1.5 : 681
Milis Need JDK 1.8 : 198
我的代码:
@Test
public void testIterationSpeed() {
List<Integer> data = new ArrayList<>();
for (int i = 0; i < 100000000; i++) {
data.add(i);
}
/*Style Java 1.4*/
long dummySum = 0;
long beforeStartJDK14 = System.currentTimeMillis();
for (int i = 0; i < data.size(); i++) {
dummySum += data.get(i);
}
long afterPrintJDK14 = System.currentTimeMillis();
/*Style Java 1.5*/
dummySum = 0;
long beforeStartJDK15 = System.currentTimeMillis();
for (Integer i : data) {
dummySum += i;
}
long afterPrintJDK15 = System.currentTimeMillis();
/* Java 1.8 */
long beforeStartJDK18 = System.currentTimeMillis();
data.parallelStream().mapToLong(i -> i).sum();
long afterPrintJDK18 = System.currentTimeMillis();
System.out.println("Milis Need JDK 1.4 : " + (afterPrintJDK14 - beforeStartJDK14));
System.out.println("Milis Need JDK 1.5 : " + (afterPrintJDK15 - beforeStartJDK15));
System.out.println("Milis Need JDK 1.8 : " + (afterPrintJDK18 - beforeStartJDK18));
}
请注意,如果减小列表大小,则parallelStream的开销将过大 - 这个事实也称为Amdahl's Law。创建总和的过程与其他循环不同,因此它不是一个好的基准。
有趣的是,每种情况都比在这种情况下慢。