Java 8 - 正确高效的使用并行流
文章目录
- Pre
- 正确使用并行流,避免共享可变状态
- 高效使用并行流
- 流的数据源和可分解性
Pre
Java 8 - 并行流计算入门
正确使用并行流,避免共享可变状态
错用并行流而产生错误的首要原因,就是使用的算法改变了某些共享状态。下面是另一种实现对前n个自然数求和的方法,但这会改变一个共享累加器:
public static long sideEffectSum(long n) {Accumulator accumulator = new Accumulator();LongStream.rangeClosed(1, n).forEach(accumulator::add);return accumulator.total;
}
public class Accumulator {public long total = 0;public void add(long value) { total += value; }
}
有什么问题呢?
它在本质上就是顺序的。每次访问 total 都会出现数据竞争。如果用同步来修复,那就完全失去并行的意义了。
为了说明这一点,让我们试着把 Stream 变成并行的:
public static long sideEffectParallelSum(long n) {Accumulator accumulator = new Accumulator();LongStream.rangeClosed(1, n).parallel().forEach(accumulator::add);return accumulator.total;
}
测试下,输出
性能无关紧要了,唯一要紧的是每次执行都会返回不同的结果,都离正确值差很远。这是由于多个线程在同时访问累加器,执行 total += value ,而这却不是一个原子操作。问题的根源在于, forEach 中调用的方法有副作用它会改变多个线程共享的对象的可变状态。
要是你想用并行 Stream 又不想引发类似的意外,就必须避免这种情况。
所以共享可变状态会影响并行流以及并行计算,要避免共享可变状态,确保并行 Stream 得到正确的结果。
高效使用并行流
是否有必要使用并行流?
- 如果有疑问,多次测试结果。把顺序流转成并行流轻而易举,但却不一定是好事
- 留意装箱。自动装箱和拆箱操作会大大降低性能
Java 8中有原始类型流( IntStream 、LongStream 、 DoubleStream )来避免这种操作,但?有可能都应该用这些流。
- 有些操作本身在并行流上的性能就比顺序流差。特别是 limit 和 findFirst 等依赖于元素顺序的操作,它们在并行流上执行的代价非常大。
例如, findAny 会比 findFirst 性能好,因为它不一定要按顺序来执行。可以调用 unordered 方法来把有序流变成无序流。那么,如果你需要流中的n个元素而不是专门要前n个的话,对无序并行流调用limit 可能会比单个有序流(比如数据源是一个 List )更高效。
- 还要考虑流的操作流水线的总计算成本。
设N是要处理的元素的总数,Q是一个元素通过流水线的大致处理成本,则N*Q就是这个对成本的一个粗略的定性估计。Q值较高就意味着使用并行流时性能好的可能性比较大。
对于较小的数据量,选择并行流几乎从来都不是一个好的决定。并行处理少数几个元素的好处还?不上并行化造成的额外开销
要考虑流背后的数据结构是否易于分解。
例如, ArrayList 的拆分效率比 LinkedList高得多,因为前者用不着遍历就可以平均拆分,而后者则必须遍历。
另外,用 range 工厂方法创建的原始类型流也可以快速分解。
- 流自身的特点,以及流水线中的中间操作修改流的方式,都可能会改变分解过程的性能。
例如,一个 SIZED 流可以分成大小相等的两部分,这样每个部分都可以比较高效地并行处理,但筛选操作可能丢弃的元素个数却无法预测,导致流本身的大小未知。
- 还要考虑终端操作中合并步骤的代价是大是小(例如 Collector 中的 combiner 方法)
如果这一步代价很大,那么组合每个子流产生的部分结果所付出的代价就可能会超出通过并行流得到的性能提升。
流的数据源和可分解性
最后, 并行流背后使用的基础架构是Java 7中引入的分支/合并框架了解它的内部原理至关重要,下一篇搞起
Java 8 - 正确高效的使用并行流相关推荐
- Java8 并行流(parallelStream)原理分析及注意事项
文章目录 前言 一.parallelStream是什么 二.parallelStream原理分析 1.Fork/Join框架 1.1 work-stealing(工作窃取算法) 1.2 常用方法 2. ...
- 【Java8实战】并行流
引言 在前面,学习使用Lambda表达式的过程中,对于集合的处理,都会使用到Stream流处理.为了提高性能,我们可以使用parallelStream并行流. 并行流 并行流就是一个把内容分成多个数据 ...
- collect() java_java-确保可以在并行流上订购.collect吗?
TL; DR 是的,订单得到保证. Stream.collect()API文档 出发点是看什么决定减少是否同时发生. Stream.collect()的描述如下: 如果流是并行的,并且CH_ID是并发 ...
- 精通lambda表达式:java多核编程_Java8 Lambda表达式和流操作如何让你的代码变慢5倍...
有许许多多关于 Java 8 中流效率的讨论,但根据 Alex Zhitnitsky 的测试结果显示:坚持使用传统的 Java 编程风格--iterator 和 for-each 循环--比 Java ...
- 跟我学 Java 8 新特性之 Stream 流(四)并行流
转载自 跟我学 Java 8 新特性之 Stream 流(四)并行流 随着对流API认识的慢慢深入,本章我们要讨论的知识点是流API里面的并行流了. 在开始讨论并行流之前,我先引发一下大家的思考, ...
- java stream 有序_Java8新特性之Stream流专题四 并行流
随着对流API认识的慢慢深入,本章我们要讨论的知识点是流API里面的并行流了. 在开始讨论并行流之前,我先引发一下大家的思考,就你看到这篇文章的时间,你们是不是经常听到,Intel i7 CPU什么8 ...
- java设置并行度_控制Java并行流的并行度
java设置并行度 在掌握了这些新功能之后,随着Java 9的最新发布,我们有了许多新功能可以用来改进我们的解决方案. Java 9的发布也是修改我们是否掌握Java 8功能的好时机. 在这篇文章中, ...
- 控制Java并行流的并行度
在掌握了这些新功能之后,随着Java 9的最新发布,我们有了许多新功能可以用来改进我们的解决方案. Java 9的发布也是修改我们是否掌握Java 8功能的好时机. 在本文中,我想解决关于Java并行 ...
- 拥抱 Java 8 并行流:执行速度飞起
点击上方 "程序员小乐"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 关注订阅号「程序员小乐」,收看更多精彩内容 每日英文 I'm gratefu ...
最新文章
- 在Cuda上部署量化模型
- 网站优化之如何辨别关键词的相关性?
- Qt Creator共享项目设置
- Useful code snippet to parse the key value pairs in URL
- html5教学文档笔记,4.HTML 教程- (HTML5 基础)
- 如何从数据库中筛选出达成指定里程碑节点的项目_如何用共识算法构建区块链共识网络?...
- 给列表项标记添加自定义图像
- Java学生管理系统项目
- Unity shader入门精要-第一章笔记
- 注册表-注册表被禁用如何处理
- OCR图形识别技术在爬虫中的应用
- MATLAB双目标定步骤
- 混合多云时代:大型主机z15的新使命
- 支持亿级标签接入,ClickHouse在广域物联网云平台架构的探索与实践
- 抖音账号和视频都没有问题,为什么我的流量还是不好?丨国仁网络资讯
- expected at least 1 bean which qualifies as autowire candidate for this ***错误的分析
- 【又是一波重点】深度解析服务器科普知识 | CSDN博文精选
- 山东省第五届ACM省赛题——Colorful Cupcakes(四维dp)
- 数加加众包深耕AI第8年,苹果加码人工智能和机器学习
- 电气隔离 电源模块 升压/充电 实测案例 150V 30W 带四个220UF电解电容并联 300ms
热门文章
- 华为鸿蒙适配计划,华为鸿蒙适配计划提前曝光,快看看有你的机型吗?
- android 之Activity间的相互跳转(通过intent构造函数)
- 机器学习——线性回归数学推导
- 为什么要使用 using namespace std
- python将列表横着输出来
- java自定义类怎么比大小_实战:Java 扑克牌比较游戏
- 二分图带权最大匹配费用流_一文掌握阻抗匹配
- 运行时错误76未找到路径怎么解决_自动化测试解决竞争问题?等待一下就行了~...
- 168. Leetcode 134. 加油站 (贪心算法-模拟题目)
- MATLAB可视化实战系列(四十)-基于MATLAB 自带手写数字集的CNN(LeNet5)手写数字识别-图像处理(附源代码)