Java8实战-总结30

Java8实战-总结30

  • 并行数据处理与性能
    • 并行流
      • 正确使用并行流
      • 高效使用并行流
    • 小结

并行数据处理与性能

并行流

正确使用并行流

错用并行流而产生错误的首要原因,就是使用的算法改变了某些共享状态。下面是另一种实现对前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;
}

用测试框架来执行这个方法,并打印每次执行的结果:

System.out.println("SideEffect parallel sum done in:" + measurePerf(ParallelStreams::sideEffectParallelSum, 10_000_000L) + " msecs");

你可能会得到类似于下面这种输出:

Result: 5959989000692
Result:7425264100768
Result: 6827235020033
Result:7192970417739
Result: 6714157975331
Result:7497810541907
Result: 6435348440385
Result:6999349840672
Result:7435914379978
Result:7715125932481
SideEffect parallel sum done in: 49 msecs

这回方法的性能无关紧要了,唯一要紧的是每次执行都会返回不同的结果,都离正确值50000005000000差很远。这是由于多个线程在同时访问累加器,执行total += value,而这一句虽然看似简单,却不是一个原子操作。问题的根源在于,forEach中调用的方法有副作用,它会改变多个线程共享的对象的可变状态。要是你想用并行Stream又不想引发类似的意外,就必须避免这种情况。
共享可变状态会影响并行流以及并行计算。记住要避免共享可变状态,确保并行Stream得到正确的结果。接下来,会提供一些实用建议,你可以由此判断什么时候可以利用并行流来提升性能。

高效使用并行流

一般而言,想给出任何关于什么时候该用并行流的定量建议都是不可能也毫无意义的,因为任何类似于“仅当至少有一千个(或一百万个或随便什么数字)元素的时候才用并行流)”的建议对于某台特定机器上的某个特定操作可能是对的,但在略有差异的另一种情况下可能就是大错特错。尽管如此,至少可以提出一些定性意见,帮你决定某个特定情况下是否有必要使用并行流。

  • 如果有疑问,测量。把顺序流转成并行流轻而易举,但却不一定是好事。我们已经指出,并行流并不总是比顺序流快。此外,并行流有时候会和你的直觉不一致,所以在考虑选择顺序流还是并行流时,第一个也是最重要的建议就是用适当的基准来检查其性能。
  • 留意装箱。自动装箱和拆箱操作会大大降低性能。Java 8中有原始类型流(IntStreamLongStreamDoubleStream)来避免这种操作,但凡有可能都应该用这些流。
  • 有些操作本身在并行流上的性能就比顺序流差。特别是limitfindFirst等依赖于元素顺序的操作,它们在并行流上执行的代价非常大。例如,findAny会比findFirst性能好,因为它不一定要按顺序来执行。你总是可以调用unordered方法来把有序流变成无序流。那么,如果你需要流中的n个元素而不是专门要前n个的话,对无序并行流调用limit可能会比单个有序流(比如数据源是一个List)更高效。
  • 还要考虑流的操作流水线的总计算成本。设N是要处理的元素的总数,Q是一个元素通过流水线的大致处理成本,则N*Q就是这个对成本的一个粗略的定性估计。Q值较高就意味着使用并行流时性能好的可能性比较大。
  • 对于较小的数据量,选择并行流几乎从来都不是一个好的决定。并行处理少数几个元素的好处还抵不上并行化造成的额外开销。
  • 要考虑流背后的数据结构是否易于分解。例如,ArrayList的拆分效率比LinkedList高得多,因为前者用不着遍历就可以平均拆分,而后者则必须遍历。另外,用range工厂方法创建的原始类型流也可以快速分解。
  • 流自身的特点,以及流水线中的中间操作修改流的方式,都可能会改变分解过程的性能。例如,一个SIZED流可以分成大小相等的两部分,这样每个部分都可以比较高效地并行处理,但筛选操作可能丢弃的元素个数却无法预测,导致流本身的大小未知。
  • 还要考虑终端操作中合并步骤的代价是大是小(例如Collector中的combiner方法)。如果这一步代价很大,那么组合每个子流产生的部分结果所付出的代价就可能会超出通过并行流得到的性能提升。

下表按照可分解性总结了一些流数据源适不适于并行。 流的数据源和可分解性:在这里插入图片描述

小结

  • 内部迭代让你可以并行处理一个流,而无需在代码中显式使用和协调不同的线程。
  • 虽然并行处理一个流很容易,却不能保证程序在所有情况下都运行得更快。并行软件的行为和性能有时是违反直觉的,因此一定要测量,确保你并没有把程序拖得更慢。
  • 像并行流那样对一个数据集并行执行操作可以提升性能,特别是要处理的元素数量庞大,或处理单个元素特别耗时的时候。
  • 从性能角度来看,使用正确的数据结构,如尽可能利用原始流而不是一般化的流,几乎总是比尝试并行化某些操作更为重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ 发送顺序消息

文章目录 顺序消息应用场景消息组(MessageGroup)顺序性生产的顺序性MQ 存储的顺序性消费的顺序性 rocketmq-client-java 示例(gRPC 协议)1. 创建 FIFO 主题生产者代码消费者代码解决办法解决后执行结果 rocketmq-client 示例&…

Hbase工作原理

Hbase:HBase 底层原理详解(深度好文,建议收藏) - 腾讯云开发者社区-腾讯云 Hbase架构图 同一个列族如果有多个store,那么这些store在不同的region Hbase写流程(读比写慢) MemStore Flush Hbas…

Python运算符、函数与模块和程序控制结构

给我家憨憨写的python教程 ——雁丘 Python运算符、函数与模块和程序控制结构 关于本专栏一 运算符1.1 位运算符1.1.1 按位取反1.1.2 按位与1.1.3 按位或1.1.4 按位异或1.1.5 左移位 1.2 关系运算符1.3 运算顺序1.4 运算方向 二 函数与模块2.1 内建函数2.2 库函数2.2.1 标准库…

【pytest】 pytest拓展功能 PermissionError问题

目录 1. pytest-html 1.1 PermissionError: [Errno 13] Permission denied: D:\\software\\python3\\anconda3\\Lib\\site-packages\\pytest_html\\__pycache__\\tmp_ttoasov 1.2错误原因 2. 失败用例重试 3. 用例并行执行 pytest-parallel 1. pytest-html 管理员打开 A…

「聊设计模式」之建造者模式(Builder)

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅! 前言 设计模式是众多优秀软件开发实践的总结和提炼,…

前端VUE---JS实现数据的模糊搜索

实现背景 因为后端实现人员列表返回&#xff0c;每次返回的数据量在100以内&#xff0c;要求前端自己进行模糊搜索 页面实现 因为是实时更新数据的&#xff0c;就不需要搜索和重置按钮了 代码 HTML <el-dialogtitle"团队人员详情":visible.sync"centerDi…

C#通过重写Panel改变边框颜色与宽度的方法

在C#中,Panel控件是一个容器控件,用于在窗体或用户控件中创建一个可用于容纳其他控件的面板。Panel提供了一种将相关控件组合在一起并进行布局的方式。以下是Panel控件的详细使用方法: 在窗体上放置 Panel 控件: 在 Visual Studio 的窗体设计器中,从工具箱中拖动并放置一…

WebGL 视图矩阵、模型视图矩阵

目录 立方体由三角形构成 视点和视线 视点、观察目标点和上方向 视点&#xff1a; 观察目标点&#xff1a; 上方向&#xff1a; 在WebGL中&#xff0c;观察者的默认状态应该是这样的&#xff1a; 视图矩阵程序&#xff08;LookAtTriangles.js&#xff09; 实际上&…

Matlab论文插图绘制模板第114期—带图形标记的图

之前的文章中&#xff0c;分享了Matlab带线标记的图&#xff1a; 带阴影标记的图&#xff1a; 带箭头标记的图&#xff1a; 进一步&#xff0c;分享一下带图形标记的图&#xff0c;先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&…

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单AdaptiveTextSelectionToolba样式UI效果

flutter开发实战-自定义长按TextField输入框剪切、复制、选择全部菜单样式UI效果 在开发过程中&#xff0c;需要长按TextField输入框cut、copy设置为中文“复制、粘贴”&#xff0c;我首先查看了TextField中的源码&#xff0c;看到了ToolbarOptions、AdaptiveTextSelectionToo…

深度学习中安装了包但是依然导入(import)失败这一问题,例如pytorch环境下已经安装了scikit-learn但是import不了

在跑深度学习模型的时候我们要先搭建pytorch环境&#xff0c;这个环境跟windows环境是不同的&#xff0c;我们默认在windows中安装的包在当前的虚拟环境中读取不到&#xff0c;所以导致我们明明安装了包但是依然在实际的导入中(import)报错。解决办法就是我们去虚拟环境中安装包…

linux驱动开发day6--(epoll实现IO多路复用、信号驱动IO、设备树以及节点和属性解析相关API使用)

一、IO多路复用--epoll实现 1.核心&#xff1a; 红黑树、一张表以及三个接口、 2.实现过程及API 1&#xff09;创建epoll句柄/创建红黑树根节点 int epfdepoll_create(int size--无意义&#xff0c;>0即可)----------成功&#xff1a;返回根节点对应文件描述符&#xff…

构建无缝的服务网格体验:分享在生产环境中构建和管理服务网格的最佳实践

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

容器的数据卷

容器的数据卷 操作数据卷 # 基本格式 docker volume [common] # 创建一个volume docker volume create # 显示一个或多个volume docker volume inspect # 列出所以的volume docker volume ls # 删除未使用的volume docker volume prune # 删除一个或多个volume docker volume…

双节履带机械臂小车实现蓝牙遥控功能

1.功能描述 本文示例所实现的功能为&#xff1a;采用蓝牙远程遥控双节履带机械臂小车进行运动。 2.结构说明 双节履带机械臂小车&#xff0c;采用履带底盘&#xff0c;可适用于任何复杂地形。 前节履带抬起高度不低于10cm&#xff0c;可用于履带车进行爬楼行进。 底盘上装有一…

mybatis学习记录(三)-----关于SQL Mapper的namespace

关于SQL Mapper的namespace 视频总结笔记&#xff1a; 在SQL Mapper配置文件中<mapper>标签的namespace属性可以翻译为命名空间&#xff0c;这个命名空间主要是为了防止SQL id 冲突的。 创建CarMapper2.xml文件&#xff0c;代码如下&#xff1a; CarMapper2.xml: <?…

用Python判断是否为闰年并计算生肖年

1 问题 润平年以及生肖是新的一年到来我们应该了解的信息。那么如何利用python程序计算快速计算该年为什么年&#xff1f; 2 方法 利用if条件判断语句实现。 代码清单 1 year eval(input(请输入咨询的年份:))if (year % 4 0 and year %100 ! 0) or year % 400 0: print(…

java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…

RocketMQ快速实战以及集群架构详解

⼀、 MQ 简介 MQ &#xff1a; MessageQueue &#xff0c;消息队列。是在互联⽹中使⽤⾮常⼴泛的⼀系列服务中间件。 这个词可以分两个部分来看&#xff0c;⼀是Message &#xff1a;消息。消息是在不同进程之间传递的数据。这些进程可以部署在同⼀台机器上&#xff0c;也可以…

17. 电话号码的字母组合

题目链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 思路&#xff1a; 数字对应字母用map(这里不好用&#xff09;&#xff0c;还是用数组映射&#xff0c;因为这里的映射表是个静态的 组合的思想。比如2,3就是需要选两个字母即搜…