【发布时间】:2022-06-16 01:32:27
【问题描述】:
我有大约 1000000 个段落的数据库记录,每个段落大约 500 个字符。通过阅读所有记录,我需要得到按使用次数从多到少排序的字母列表。
我通过创建多达 1000000 个流来模拟数据库读取,然后并行处理流
final Map<Character, Long> charCountMap = new ConcurrentHashMap<>();
for (char c = 'a'; c <= 'z'; c++) {
charCountMap.put(c, 0l);
}
System.out.println("Parallel Stream");
long start = System.currentTimeMillis();
Stream.iterate(0, i -> i).limit(1000000).parallel() //mock database stream
.forEach(i-> RandomStringUtils.randomAlphanumeric(500)
.toLowerCase().chars().mapToObj(c -> Character.valueOf((char) c)).filter(c -> c >= 97 && c <= 122)
.forEach(c -> charCountMap.compute(c, (k, v) -> v + 1))); //update ConcurrentHashMap
long end = System.currentTimeMillis();
System.out.println("Parallel Stream time spent :" + (end - start));
System.out.println("Serial Stream"); start = System.currentTimeMillis();
Stream.iterate(0, i -> i).limit(1000000) //mock database stream
.forEach(i-> RandomStringUtils.randomAlphanumeric(500)
.toLowerCase().chars().mapToObj(c -> Character.valueOf((char) c)).filter(c -> c >= 97 && c <= 122)
.forEach(c -> charCountMap.compute(c, (k, v) -> v + 1)));
end = System.currentTimeMillis();
System.out.println("Serial Stream time spent :" + (end - start));
我最初认为并行流会更快,即使流大于 100,000 的预期开销也是如此。然而,测试表明即使处理 1,000,000 条记录,串行流也比并行快约 5 倍。
我怀疑是因为更新了 ConcurrentHashMap。但是当我删除它并用空函数更改时,仍然存在显着的性能差距。
我的数据库模拟调用或我使用并行流的方式有什么问题吗?
【问题讨论】:
-
这里是凭记忆,所以要持保留态度,但是在计算经过的时间时,您应该使用
System.nanoTime(),而不是System.currentTimeMillis()。如果您必须自己进行基准测试,这个question 是一个很好的来源。 -
如果没有热身运行和适当的基准测试,您将无法得出任何结论。只需尝试交换串行和并行代码部分的顺序,您可能会得出相反的结论,因为第一次迭代测试最慢。此外,随机生成器可能不是线程安全的(无法判断,因为您没有显示代码),这可能意味着并行版本永远不会是最快的。
-
我已经交换了订单并得到了相同的结果。我使用的 RandomStringUtils 来自 Apache commons-lang 库
标签: java concurrency stream parallelstream