草庐IT

求求你们了,别再乱用 parallelStream 了,速度竟然比 Stream 还要慢!!

Java技术栈 2023-04-16 原文

parallelStream 一定更快吗?

大家都知道 Stream 分为顺序流和并行流:

  • stream(顺序流)
  • parallelStream(并行流)

它们最大的区别就是 parallelStream 支持并行化处理,所以效率较 stream(顺序流)肯定是要更快的。这篇不会介绍 Stream 基础,Stream 系列我之前写过一个专题了,不懂的关注公众号Java技术栈,然后在公众号 Java 教程菜单中阅读。

然而你确定 parallelStream 一定要更快吗?

栈长写了一段排序的示例,分别用 stream 和 parallelStream,对 100 ~ 10000000 条数据的集合进行排序,来看下执行效率究竟如何!

顺序流排序:

/**
 * 顺序流排序
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
private static void streamSort() {
    long start = System.currentTimeMillis();
    List<SortTest.User> list = new ArrayList<>(LIST);

    list.stream().sorted(SortTest.User::compareAge).collect(Collectors.toList());

    System.out.println("\nList size: " + list.size() + " Stream.sorted: " + (System.currentTimeMillis() - start));
}

并行流排序:

/**
 * 并行流排序
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
private static void parallelStreamSort() {
    long start = System.currentTimeMillis();
    List<SortTest.User> list = new ArrayList<>(LIST);

    list.parallelStream().sorted(SortTest.User::compareAge).collect(Collectors.toList());

    System.out.println("List size: " + list.size() + " ParallelStream.sorted: " + (System.currentTimeMillis() - start));
}

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

执行结果如下:

List size: 10000000 Stream.sorted: 202
List size: 10000000 ParallelStream.sorted: 402

List size: 1000000 Stream.sorted: 53
List size: 1000000 ParallelStream.sorted: 15

List size: 100000 Stream.sorted: 1
List size: 100000 ParallelStream.sorted: 2

List size: 10000 Stream.sorted: 0
List size: 10000 ParallelStream.sorted: 1

List size: 1000 Stream.sorted: 0
List size: 1000 ParallelStream.sorted: 1

List size: 100 Stream.sorted: 0
List size: 100 ParallelStream.sorted: 0

在 100000 以下是没什么区别的;

在 1000000 左右 ParallelStream 虽然领先 Stream,但也不是绝对每次都领先,经过不断测试,这个数据量区间的测试两者会互相领先;

在 10000000 左右就很稳定了,ParallelStream 几乎比 Stream 慢了 2 倍!

现在你可能会有疑问了,为什么会这样?

栈长起初也有疑问,并行流(ParallelStream)怎么会比顺序流(Stream)还要慢。。

其实我后面想想也就明白了,并行流(ParallelStream)的背后其实是 Java7 开始支持的 Fork/Join,即把一个大任务拆分成 N 个小任务,然后最终合并各个子任务的结果,所以对于子任务线程的拆分、创建、结果合并等操作都需要不少的开销,特别是线程的创建。

所以这种不耗时的简单排序操作事实上是不适用于并行流(ParallelStream)的,它所带来的线程创建的损耗可能还会比顺序流(Stream)还要更慢。

最新 Java 8+ 面试题也都整理好了,点击Java面试库小程序在线刷题。

什么时候用 ParallelStream?

既然使用 Fork/Join 是会有损耗的,那对于单条数据的处理的时间最好是理论上要超过用并行流(ParallelStream)本身的损耗,这种情况下就比较合适。

也就是说,如果对于流中的每条数据的处理比较费时间,并且没有顺序要求,这种场景下用并行流(ParallelStream)会更快,更合适。

来看下面这个示例:

顺序流数据处理:

/**
 * 顺序流数据处理
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
private static void streamProcess() {
    long start = System.currentTimeMillis();
    List<SortTest.User> list = new ArrayList<>(LIST);

    list.stream().map(StreamSpeedTest::process).collect(Collectors.toList());

    System.out.println("\nList size: " + list.size() + " Stream process: " + (System.currentTimeMillis() - start));
}

并行流数据处理:

/**
 * 并行流数据处理
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
private static void parallelStreamProcess() {
    long start = System.currentTimeMillis();
    List<SortTest.User> list = new ArrayList<>(LIST);

    list.parallelStream().map(StreamSpeedTest::process).collect(Collectors.toList());

    System.out.println("List size: " + list.size() + " ParallelStream process: " + (System.currentTimeMillis() - start));
}

数据处理:

/**
 * 数据处理
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
private static SortTest.User process(SortTest.User user) {
    try {
        user.setName(user.getName() + ": process");
        Thread.sleep(5);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return user;
}

注意: 这里加了个休眠 5 毫秒,为了体现真实的处理数据耗时。

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

并行流排序:

List size: 1000 Stream process: 5750
List size: 1000 ParallelStream process: 745

List size: 100 Stream process: 566
List size: 100 ParallelStream process: 77

结果很明显了,不管测试多少次,并行流(ParallelStream)的处理速度都要比顺序流(Stream)要快几倍!!我这里只测试了 100 和 1000 条数据,因为 10000 条以上的数据用顺序流(Stream)可能要等非常久。

而且我程序中的处理逻辑只休眠了 5 毫秒,如果实际处理单条数据的耗时要比这个更长,那并行流(ParallelStream)的处理效率还会更明显。

总结

稍微总结下:

  • stream: 适用于避免线程安全问题、要求顺序执行、数据处理简单不耗时的任务;
  • parallelStream: 适用于不存在线程安全问题、不需要顺序性执行、数据处理比较耗时的任务;

所以,你学废了吗?赶紧发给身边的同事看看吧,别再乱用 parallelStream 了!用的不好,存在线程安全问题不说,效率上可能还会适得其反。

大家如果对 Java 8 新增的知识点(Lambda、Stream、函数式接口等)还不会用的可以关注公众号:Java技术栈,在 Java 教程菜单中阅读,Java 8+ 系列教程我都写了一堆了。

本文所有完整示例源代码已经上传:

https://github.com/javastacks/javastack

欢迎 Star 学习,后面 Java 示例都会在这上面提供!

好了,今天的分享就到这里了,后面栈长会分享更多好玩的 Java 技术和最新的技术资讯,关注公众号Java技术栈第一时间推送,我也将主流 Java 面试题和参考答案都整理好了,在公众号后台回复关键字 "面试" 进行刷题。

最后,觉得我的文章对你用收获的话,动动小手,给个在看、转发,原创不易,栈长需要你的鼓励。

版权声明: 本文系公众号 "Java技术栈" 原创,转载、引用本文内容请注明出处,抄袭、洗稿一律投诉侵权,后果自负,并保留追究其法律责任的权利。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

有关求求你们了,别再乱用 parallelStream 了,速度竟然比 Stream 还要慢!!的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. java - Ruby 和 Java 的速度 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。在我在网上找到的每个基准测试中,Ruby似乎都很慢,比Java慢得多。Ruby的人只是说这无关紧要。您能举个例子说明RubyonRails(以及Ruby本身)的速度真的无关紧要吗?

  3. ruby-on-rails - Ruby 的 range step 方法导致执行速度很慢? - 2

    我有这段代码:date_counter=Time.mktime(2011,01,01,00,00,00,"+05:00")@weeks=Array.new(date_counter..Time.now).step(1.week)do|week|logger.debug"WEEK:"+week.inspect@weeks从技术上讲,代码有效,输出:SatJan0100:00:00-05002011SatJan0800:00:00-05002011SatJan1500:00:00-05002011etc.但是执行时间完全是垃圾!每周计算大约需要四秒钟。我在这段代码中是否遗漏了一些奇怪的低效

  4. ruby-on-rails - XPath 或 CSS 解析速度更快(对于 HTML 文件上的 Nokogiri)? - 2

    我想知道NokogiriXPath或CSS解析是否可以更快地处理HTML文件。速度有何不同? 最佳答案 Nokogiri没有XPath或CSS解析。它将XML/HTML解析为单个DOM,然后您可以使用CSS或XPath语法进行查询。CSS选择器在要求libxml2执行查询之前在内部转换为XPath。因此(对于完全相同的选择器)XPath版本会快一点点,因为CSS不需要先转换成XPath。但是,您的问题没有通用答案;这取决于您选择的是什么,以及您的XPath是什么样的。很有可能,您不会编写与Nokogiri创建的相同的XPath。例如

  5. ruby-on-rails - 是什么导致了这个 rails ioerror closed stream? - 2

    我有一个Rails应用程序,在开发模式下运行(使用sqlite数据库)。该应用程序的目的是允许用户通过Java客户端上传文件。如果用户要上传一个文件夹,会递归上传里面的所有文件。如果用户要上传文件,文件将正常上传。这是我收到的错误:IOErrorinUploadedFilesController#newclosedstream这是应用程序跟踪:/usr/lib/ruby/1.8/tempfile.rb:167:in`close'/usr/lib/ruby/1.8/tempfile.rb:167:in`callback'/var/lib/gems/1.8/gems/activesuppo

  6. ruby - proc、Proc.new、lambda 和 stabby lambda 之间的速度差异 - 2

    过程和lambdadiffer关于方法范围和return关键字的效果。我对它们之间的性能差异很感兴趣。我写了一个测试,如下所示:deftime(&block)start=Time.nowblock.callp"thattook#{Time.now-start}"enddeftest(proc)time{(0..10000000).each{|n|proc.call(n)}}enddeftest_block(&block)time{(0..10000000).each{|n|block.call(n)}}enddefmethod_testtime{(1..10000000).each{|

  7. Two-Stream Convolutional Networks for Action Recognition in Videos双流网络论文精读 - 2

    Two-StreamConvolutionalNetworksforActionRecognitioninVideos双流网络论文精读论文:Two-StreamConvolutionalNetworksforActionRecognitioninVideos链接:https://arxiv.org/abs/1406.2199本文是深度学习应用在视频分类领域的开山之作,双流网络的意思就是使用了两个卷积神经网络,一个是SpatialstreamConvNet,一个是TemporalstreamConvNet。此前的研究者在将卷积神经网络直接应用在视频分类中时,效果并不好。作者认为可能是因为卷积神经

  8. ruby-on-rails - 如何加快为 rspec 测试创建 5,000 条记录的速度? - 2

    我正在使用RubyonRails3.2.2、FactoryGirl3.1.0、FactoryGirlRails3.1.0、Rspec2.9.0和RspecRails2.9.0。为了测试我的应用程序,我必须在数据库中创建大量记录(大约5000条),但是该操作非常慢(创建记录需要10多分钟)。我这样进行:before(:each)do5000.timesdoFactoryGirl.create(:article,)endend如何改进我的规范代码以加快速度?注意:可能速度较慢是由在每个文章创建过程前后运行的(5)个文章回调引起的,但我可以跳过这些(因为我唯一需要测试的是文章和不是关联的模型

  9. ruby-on-rails - 测试速度 : ActiveRecord use_transactional_fixtures vs. DatabaseCleaner.strategy = :transaction - 2

    从来源(database_cleaner,active_record)来看,它们应该同样快。但是有人声称使用database_cleaner的事务策略会降低Controller和模型规范的速度(forexample)。我手头没有用于基准测试的大型测试套件。任何人有任何见解或比较两者? 最佳答案 我花了一点时间在广泛使用ActiveRecord固定装置的中型代码库上比较两者。当我将其切换为使用DatabaseCleaner而不是use_transactional_fixtures时,模型规范开始花费大约两倍的时间。在进行了与您相同的比

  10. AiBote 2022 新研发的自动化框架,支持 Android 和 Windows 系统。速度非常快 - 2

    Ai-Bot基于流行的Node.js和JavaScript语言的一款新自动化框架,支持Windows和Android自动化。1、Windowsxpath元素定位算法支持支持Windows应用、.NET、WPF、Qt、Java和Electron客户端程序和ie、edgechrome浏览器2、Android支持原生APP和H5界面,元素定位速度是appium十倍,无线远程自动化操作多台安卓设备3、基于opencv图色算法,支持找图和多点找色,1080*2340全分辨率找图50MS以内4、内置免费OCR人工智能技术,无限制获取图片文字和找字功能。5、框架协议开源,除官方node.jsSDK外,用户可

随机推荐