阅读更多

0顶
0踩

编程语言

原创新闻 Java8中流的性能

2017-11-16 09:15 by 副主编 jihong10102006 评论(0) 有11358人浏览
引用
原文:Performance With Java8 Streams
作者:Arun Pandey
翻译:雁惊寒

摘要:本文介绍了Java8中流的几个特性,以告诫开发者流并不是高性能的代名词,需谨慎使用流。以下是译文。

流(Stream)是Java8为了实现最佳性能而引入的一个全新的概念。在过去的几年中,随着硬件的持续发展,编程方式已经发生了巨大的改变,程序的性能也随着并行处理、实时、云和其他一些编程方法的出现而得到了不断提高。

Java8中,流性能的提升是通过并行化(parallelism)、惰性(Laziness)和短路操作(short-circuit operations)来实现的。但它也有一个缺点,在选择流的时候需要非常小心,因为这可能会降低应用程序的性能。

下面来看看这三项支撑起流强大性能的因素吧。

并行化

流的并行化充分利用了硬件的相关功能。由于现在计算机上通常都有多个CPU核心,所以在多核系统中如果只使用一个线程则会极大地浪费系统资源。设计和编写多线程应用非常具有挑战性,并且很容易出错,因此,流存在两种实现:顺序和并行。使用并行流非常简单,无需专业知识即可轻松处理多线程问题。

在Java的流中,并行化是通过Fork-Join原理来实现的。根据Fork-Join原理,系统会将较大的任务切分成较小的子任务(称之为forking),然后并行处理这些子任务以充分利用所有可用的硬件资源,最后将结果合并起来(称之为Join)组成完整的结果。

在选择顺序和并行的时候,需要非常谨慎,因为并行并一定意味着性能会更好。

让我们来看一个例子。

StreamTest.java:
package test;
import java.util.ArrayList;
import java.util.List;
public class StreamTest {
 static List < Integer > myList = new ArrayList < > ();
 public static void main(String[] args) {
  for (int i = 0; i < 5000000; i++)
   myList.add(i);
  int result = 0;
  long loopStartTime = System.currentTimeMillis();
  for (int i: myList) {
   if (i % 2 == 0)
    result += i;
  }
  long loopEndTime = System.currentTimeMillis();
  System.out.println(result);
  System.out.println("Loop total Time = " + (loopEndTime - loopStartTime));
  long streamStartTime = System.currentTimeMillis();
  System.out.println(myList.stream().filter(value -> value % 2 == 0).mapToInt(Integer::intValue).sum());
  long streamEndTime = System.currentTimeMillis();
  System.out.println("Stream total Time = " + (streamEndTime - streamStartTime));
  long parallelStreamStartTime = System.currentTimeMillis();
  System.out.println(myList.parallelStream().filter(value -> value % 2 == 0).mapToInt(Integer::intValue).sum());
  long parallelStreamEndTime = System.currentTimeMillis();
  System.out.println("Parallel Stream total Time = " + (parallelStreamEndTime - parallelStreamStartTime));
 }
}

运行结果:
820084320
Loop total Time = 17
820084320
Stream total Time = 81
820084320
Parallel Stream total Time = 30

正如你所见,在这种情况下,for循环更好。因此,在没有正确的分析之前,不要用流代替for循环。在这里,我们可以看到,并行流的性能比普通流更好。

注意:结果可能会因为硬件的不同而不同。

惰性

我们知道,Java8的流有两种类型的操作,分别为中间操作(Intermediate)和最终操作(Terminal)。这两种操作分别用于处理和提供最终结果。如果最终操作不与中间操作相关联,则无法执行。

总之,中间操作只是创建另一个流,不会执行任何处理,直到最终操作被调用。一旦最终操作被调用,则开始遍历所有的流,并且相关的函数会逐一应用到流上。中间操作是惰性操作,所以,流支持惰性。

注意:对于并行流,并不会在最后逐个遍历流,而是并行处理流,并且并行度取决于机器CPU核心的个数。

考虑一下这种情况,假设我们有一个只有中间操作的流片段,而最终操作要稍后才会添加到应用中(可能需要也可能不需要,取决于用户的需求)。在这种情况下,流的中间操作将会为最终操作创建另一个流,但不会执行实际的处理。这种机制有助于提高性能。

我们来看一下有关惰性的例子:
StreamLazinessTest.java:
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamLazinessTest {
 /** Employee class **/
 static class Employee {
  int id;
  String name;
  public Employee(int id, String name) {
   this.id = id;
   this.name = name;
  }
  public String getName() {
   return this.name;
  }
 }
 public static void main(String[] args) throws InterruptedException {
  List < Employee > employees = new ArrayList < > ();
  /** Creating the employee list **/
  for (int i = 1; i < 10000000; i++) {
   employees.add(new StreamLazinessTest.Employee(i, "name_" + i));
  }
  /** Only Intermediate Operations; it will just create another streams and 
   * will not perform any operations **/
  Stream < String > employeeNameStreams = employees.parallelStream().filter(employee -> employee.id % 2 == 0)
   .map(employee -> {
    System.out.println("In Map - " + employee.getName());
    return employee.getName();
   });
  /** Adding some delay to make sure nothing has happen till now **/
  Thread.sleep(2000);
  System.out.println("2 sec");
  /** Terminal operation on the stream and it will invoke the Intermediate Operations
   * filter and map **/
  employeeNameStreams.collect(Collectors.toList());
 }
}

运行上面的代码,你可以看到在调用最前操作之前,中间操作不会被执行。

短路行为

这是优化流处理的另一种方法。 一旦条件满足,短路操作将会终止处理过程。 有许多短路操作可供使用。 例如,anyMatch、allMatch、findFirst、findAny、limit等等。

我们来看一个例子。

StreamShortCircuitTest.java:
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamShortCircuitTest {
 /** Employee class **/
 static class Employee {
  int id;
  String name;
  public Employee(int id, String name) {
   this.id = id;
   this.name = name;
  }
  public int getId() {
   return this.id;
  }
  public String getName() {
   return this.name;
  }
 }
 public static void main(String[] args) throws InterruptedException {
  List < Employee > employees = new ArrayList < > ();
  for (int i = 1; i < 10000000; i++) {
   employees.add(new StreamShortCircuitTest.Employee(i, "name_" + i));
  }
  /** Only Intermediate Operations; it will just create another streams and 
   * will not perform any operations **/
  Stream < String > employeeNameStreams = employees.stream().filter(e -> e.getId() % 2 == 0)
   .map(employee -> {
    System.out.println("In Map - " + employee.getName());
    return employee.getName();
   });
  long streamStartTime = System.currentTimeMillis();
  /** Terminal operation with short-circuit operation: limit **/
  employeeNameStreams.limit(100).collect(Collectors.toList());
  System.out.println(System.currentTimeMillis() - streamStartTime);
 }
}

运行上面的代码,你会看到性能得到了极大地提升,在我的机器上只需要6毫秒的时间。 在这里,limit()方法在满足条件的时候会中断运行。

最后要注意的是,根据状态的不同有两种类型的中间操作:有状态(Stateful)和无状态(Stateless)中间操作。

有状态中间操作

这些中间操作需要存储状态,因此可能会导致应用程序的性能下降,例如,distinct()、sort()、limit()等等。

无状态中间操作

这些中间操作可以独立处理,因为它们不需要保存状态,例如, filter(),map()等。

在这里,我们了解到,流的出现是为了获得更高的性能,但并不是说使用了流之后性能肯定会得到提升,因此,我们需要谨慎使用。
0
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Java8中流的性能及流的几个特性

    流(Stream)是Java8为了实现最佳性能而引入的一个全新的概念。接下来通过本文给大家分享Java8中流的性能,需要的朋友参考下吧

  • java8流_Java8中流的性能

    但它也有一个缺点,在选择流的时候需要非常小心,因为这可能会降低应用程序的性能。下面来看看这三项支撑起流强大性能的因素吧。并行化流的并行化充分利用了硬件的相关功能。由于现在计算机上通常都有多个CPU核心,...

  • java流式api,Java 8 中流式API性能基准测试

    测试代码 package hello.test; import org.openjdk.jmh....368.454 ops/ms 总结 对性能敏感的程序, 建议还是用回传统的for循环 并行流并不一定会比顺序流快 java 8 的流式api, 一般情况下比不上传统的 for 循环

  • 详解Java8中流(Stream)的使用

    文章列表一、回忆Lambda表达式二、什么是流1、流只能遍历一次2、...写博客的目的就是分享给大家一起学习交流,如果您对 Java感兴趣,可以关注我,我们一起学习。 前言:还没接触过流的同学可以深入研究下此篇文章,

  • Java 8 Stream 数据流效率分析

    来源:https://blog.csdn.net/Al_assad/article/details/82356606Stream 是Java SE 8类库中新增的关键抽象,它被定义于 java.util.stream (这个包里有若干流类型:Stream代表对象引用流,此外还有一系列特化流,如 ...

  • java8stream性能_Java Stream性能–真的那么糟糕吗?

    当我阅读Angelika Langer的Java性能教程时– “ Java 8流有多快?” 我简直不敢相信,对于一个特定的操作,它们花费的时间比循环要长15倍。 流媒体性能真的会那么糟糕吗? 我必须找出答案! 巧合的是,我最近观看...

  • Java8 Lambda表达式性能问题

    有许许多多关于 Java 8 中流效率的讨论,但根据 Alex Zhitnitsky 的测试结果显示:坚持使用传统的 Java 编程风格——iterator 和 for-each 循环——比 Java 8 的实现性能更佳。 Java 8 中的 Lambda 表达式和流...

  • java8中流的相关操作

    java8为实现数据的便捷处理与并行易用引入了Stream API。 本文将介绍Stream API的一些操作以及如何创建特殊的流。

  • Java 8 Stream API 性能优化技巧

    Java 8引入了Stream API,它是一个用来处理集合数据流的API。在日常开发中,Stream API可以有效提高编程效率,改善代码可读性、代码质量和程序运行效率等。但是Stream API的高级特性也使得其在性能方面也存在不少...

  • Java8流式操作——中间操作

    } 输出结果: 补充—Java8新特性 Lambda表达式:Lambda表达式是Java 8最重要的新特性之一。它允许我们以更简洁的方式编写函数式接口的实现。Lambda表达式可以用来替代匿名内部类,使代码更加简洁和易读。 函数式接口...

  • Java 8流处理详解

    流是Java API的新成员,它允许你以声明性方式(类似SQL,只写做什么,不考虑怎么做)处理数据集合。流就是从支持数据处理操作的源生成的元素序列。源可以是集合、数组或IO资源,数据处理操作包括filter(过滤),map...

  • Java 8 之Stream API

    总结一下,Java 8的Stream API带来的好处: 声明性-更简洁,更易读 可复合-更灵活 可并行-性能更好 流简介 流到底是什么?简单定义:“从支持数据处理操作的源生成的元素序列”,下面剖析这个定义。 元素序列:像...

  • Java Stream流使用及性能分析

    Java8 中添加了一个新的接口类 Stream,相当于高级版的 Iterator,它可以通过 Lambda 表达式对集合进行大批量数据操作,或 者各种非常便利、高效的聚合数据操作。 2、为什么要使用Stream? 在 Java8 之前,我们通常...

  • java8特性lambda基本原理及性能分析

    Java8发布,Lambda表达式作为一项重要的特性随之而来。或许现在你已经在使用Lambda表达式来书写简洁灵活的代码。 Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是...

  • Java8新特性-Stream流的介绍与具体使用

    Java8新特性-stream流

  • 基于Java的家庭理财系统设计与开发-金融管理-家庭财产管理-实用性强

    内容概要:文章探讨了互联网时代的背景下开发一个实用的家庭理财系统的重要性。文中分析了国内外家庭理财的现状及存在的问题,阐述了开发此系统的目的——对家庭财产进行一体化管理,提供统计、预测功能。系统涵盖了家庭成员管理、用户认证管理、账单管理等六大功能模块,能够满足用户多方面查询及统计需求,并保证数据的安全性与完整性。设计中运用了先进的技术栈如SSM框架(Spring、SpringMVC、Mybatis),并采用MVC设计模式确保软件结构合理高效。 适用人群:对于希望科学地管理和规划个人或家庭财务的普通民众;从事财务管理相关专业的学生;有兴趣于家政学、经济学等领域研究的专业人士。 使用场景及目标:适用于日常家庭财务管理的各个场景,帮助用户更好地了解自己的消费习惯和资金状况;为目标客户提供一套稳定可靠的解决方案,助力家庭财富增长。 其他说明:文章还包括系统设计的具体方法与技术选型的理由,以及项目实施过程中的难点讨论。对于开发者而言,不仅提供了详尽的技术指南,还强调了用户体验的重要性。

  • 弹性盒子Flexbox布局.docx

    弹性盒子Flexbox布局.docx

  • 网络财务系统 SSM毕业设计 附带论文.zip

    网络财务系统 SSM毕业设计 附带论文 启动教程:https://www.bilibili.com/video/BV1GK1iYyE2B

  • 联想电脑的bios设置

    联想电脑的bios设置、图文都有

  • 1_教务处关于云南师范大学2024年大学生科研训练基金项目立项申报工作的通知 (1).zip

    1_教务处关于云南师范大学2024年大学生科研训练基金项目立项申报工作的通知 (1).zip

Global site tag (gtag.js) - Google Analytics