Java 8 嵌套循环与流和性能
为了练习 Java 8 流,我尝试将以下嵌套循环转换为 Java 8 流 API。它计算a^b的最大数字总和(a,b<100),并在我的Core i5 760上取~0.135s。
public static int digitSum(BigInteger x)
{
int sum = 0;
for(char c: x.toString().toCharArray()) {sum+=Integer.valueOf(c+"");}
return sum;
}
@Test public void solve()
{
int max = 0;
for(int i=1;i<100;i++)
for(int j=1;j<100;j++)
max = Math.max(max,digitSum(BigInteger.valueOf(i).pow(j)));
System.out.println(max);
}
我的解决方案,由于paralellism,我期望更快,实际上需要0.25s(没有0.19s):parallel()
int max = IntStream.range(1,100).parallel()
.map(i -> IntStream.range(1, 100)
.map(j->digitSum(BigInteger.valueOf(i).pow(j)))
.max().getAsInt()).max().getAsInt();
我的问题
- 我是否正确地进行了转换,或者是否有更好的方法将嵌套循环转换为流计算?
- 为什么流变体比旧变体慢得多?
- 为什么 parallel() 语句实际上将时间从 0.19 秒增加到 0.25 秒?
我知道微基准是脆弱的,并行性只值得解决大问题,但对于CPU来说,即使是0.1s也是永恒的,对吧?
更新
我使用Eclipse Kepler中的Junit 4框架进行测量(它显示了执行测试所需的时间)。
我对 a,b<1000 而不是 100 的结果:
- 传统循环 186s
- 顺序流 193s
- 并行流 55s
更新 2替换为(感谢彼得!)减少了10整秒的并行方法,使其达到45秒。没想到会有这么大的性能影响!sum+=Integer.valueOf(c+"");
sum+= c - '0';
此外,将并行度减少到CPU内核的数量(在我的例子中为4)并没有多大作用,因为它将时间减少到44.8s(是的,它增加了a和b = 0,但我认为这不会对性能产生太大影响):
int max = IntStream.range(0, 3).parallel().
.map(m -> IntStream.range(0,250)
.map(i -> IntStream.range(1, 1000)
.map(j->.digitSum(BigInteger.valueOf(250*m+i).pow(j)))
.max().getAsInt()).max().getAsInt()).max().getAsInt();