fork join框架_Fork / Join框架vs.并行流vs.ExecutorService:最终的Fork / Join基准

fork join框架

Fork / Join框架在不同配置下如何工作?

就像即将到来的《星球大战》(Star Wars)一样,围绕Java 8并行性的批评也充满了兴奋。 并行流的语法糖带来了一些炒作,就像我们在预告片中看到的新型光剑一样。 现在,有了许多使用Java进行并行处理的方法,我们希望了解性能优势和并行处理的危险。 经过260多次测试运行后,从数据中获得了一些新见解,我们希望在本文中与您分享。

分叉/加入:分叉唤醒

分叉/加入:分叉唤醒

ExecutorService与Fork / Join Framework与并行流

很久以前,在一个遥远的星系中……。 我的意思是,大约10年前,并发只能通过3rd party库在Java中使用。 随后出现了Java 5,并在语言中引入了java.util.concurrent库,该库在Doug Lea的强烈影响下。 ExecutorService可用并为我们提供了一种处理线程池的直接方法。 当然,java.util.concurrent一直在发展,并且在Java 7中引入了Fork / Join框架,该框架建立在ExecutorService线程池之上。 使用Java 8流,已经为我们提供了使用Fork / Join的简单方法,但对于许多开发人员来说仍然有点谜。 让我们找出它们之间的比较。

我们完成了两项任务,一项是CPU密集型任务,另一项是IO密集型任务,并使用相同的基本功能测试了4种不同的方案。 另一个重要因素是我们用于每个实现的线程数,因此我们也对其进行了测试。 我们使用的机器有8个内核 ,因此我们有4、8、16和32个线程的变种,以大致了解结果的发展方向。 对于每个任务,我们还尝试了单线程解决方案,您不会在图中看到它,因为执行起来要花费更长的时间。 要详细了解测试的运行方式,您可以查看下面的基础部分。 现在,让我们开始吧。

用580万行文本索引6GB文件

在此测试中,我们生成了一个巨大的文本文件,并为索引过程创建了类似的实现。 结果如下所示:

文件索引测试结果

文件索引测试结果

**单线程执行:176,267毫秒,或将近3分钟。
**请注意,图形开始于20000毫秒。

1.更少的线程将使CPU未被使用,太多的线程将增加开销

您在图表中注意到的第一件事是结果开始采用的形状–您仅从这4个数据点就可以了解每个实现的行为。 临界点在8到16个线程之间,因为某些线程在文件IO中处于阻塞状态,并且添加比内核更多的线程有助于更好地利用它们。 当有32个线程进入时,由于额外的开销,性能会变差。

比亚军快1秒:直接使用Fork / Join

除了语法糖(lambdas!我们没有提到lambdas),我们已经看到并行流的性能比Fork / Join和ExecutorService实现的更好。 6GB的文本在24.33秒内被索引。 您可以在这里信任Java来提供最佳结果。

3.但是…并行流也表现最差:唯一的变化超过了30秒

这再次提醒您并行流如何降低您的速度。 假设这种情况发生在已经运行多线程应用程序的计算机上。 在可用线程数量较少的情况下,直接使用Fork / Join实际上比通过并行流要好-5秒的差异,将这两个线程进行比较时大约要付出18%的代价。

4.不要使用图片中带有IO的默认池大小

当为并行流使用默认池大小时,机器上相同数量的内核(此处为8个内核)比16线程版本的性能差了近2秒。 如果使用默认池大小,则要加收7%的罚款。 发生这种情况的原因与阻塞IO线程有关。 还有更多的等待正在进行,因此引入更多的线程可以使我们更多地使用所涉及的CPU内核,而其他线程可以等待调度而不是空闲。

如何更改并行流的默认Fork / Join池大小? 您可以使用JVM参数更改常见的Fork / Join池大小:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=16

(默认情况下,所有Fork / Join任务都使用一个公共静态池,其大小与内核数相同。这样做的好处是,通过在不使用期间为其他任务回收线程,从而减少了资源使用。)

或者…您可以使用此技巧并在自定义Fork / Join池中运行并行流。 这将覆盖通用的Fork / Join池的默认用法,并允许您使用自己设置的池。 偷偷摸摸。 在测试中,我们使用了公共池。

5.单线程性能比最佳结果差7.25倍

并行性提供了7.25倍的改进,并且考虑到该机器具有8个内核,因此非常接近理论上的8倍预测! 我们可以将其余的归因于开销。 话虽如此,即使我们测试的最慢的并行性实现(这次是具有4个线程的并行流(30.24sec)),其性能也比单线程解决方案(176.27sec)好5.8倍。

检查数字是否为质数

在下一轮测试中,我们完全消除了IO,并检查了确定一个真正大的数字是否为素数所需的时间。 多大? 19位数字 。 1,530,692,068,127,007,263或换句话说:五百一十九亿四千三百四十四万亿三千三百八十亿八千八百八十三万三千三百三十。 啊,让我呼吸一下。 无论如何,除了运行到其平方根之外,我们没有使用任何优化,因此即使我们的大数没有除以2只是为了延长处理时间,我们也检查了所有偶数。 剧透警告:这是首要的,因此每个实现都运行相同数量的计算。

结果是这样的:

素数测试结果

素数测试结果

**单线程执行:118,127毫秒,或将近2分钟。
**请注意,图形开始于20000毫秒

1. 8和16个线程之间的差异较小

与IO测试不同,这里没有IO调用,因此8和16线程的性能几乎是相似的,除了Fork / Join解决方案。 实际上,我们已经运行了更多的测试集,以确保由于这种“异常”而在这里获得了良好的结果,但事实证明,一次又一次的相似。 我们很高兴在下面的评论部分中听到您对此的想法。

2.所有方法的最佳结果相似

我们看到所有实现都分享了大约28秒的相似最佳结果。 无论我们尝试采用哪种方法,结果都相同。 这并不意味着我们对使用哪种方法都无所谓。 查看下一个见解。

3.并行流比其他实现更好地处理线程重载

这是更有趣的部分。 通过该测试,我们再次看到运行16个线程的最高结果来自使用并行流。 此外,在此版本中,使用并行流是线程号所有变体的一个好选择。

4.单线程性能比最佳结果低4.2倍

此外,在运行计算密集型任务时使用并行性的好处几乎比使用文件IO的IO测试要差2倍。 这是有道理的,因为它是CPU密集型测试,与之前的测试不同,我们可以通过减少内核等待被IO阻塞的线程的时间来获得额外的好处。

结论

我建议您从源头上了解何时使用并行流的更多信息,并在您使用Java进行并行化时随时进行仔细的判断。 最好的方法是在暂存环境中运行与这些测试类似的测试,在此环境中您可以尝试并更好地了解要面对的挑战。 您必须注意的因素当然是运行的硬件(以及要测试的硬件)以及应用程序中的线程总数。 这包括公用的Fork / Join池和团队中其他开发人员正在处理的代码。 因此,在添加自己的并行性之前,请尝试检查它们并获得应用程序的完整视图。

基础工作

为了运行此测试,我们使用了具有8个vCPU和15GB RAM的EC2 c3.2xlarge实例。 vCPU意味着存在超线程,因此实际上我们在这里有4个物理内核,每个物理内核都像2个内核一样工作。就OS调度程序而言,我们在这里有8个内核。 为了尽可能使它公平,每个实现都运行了10次,并且我们采用了运行2到9的平均运行时间。这是260次测试运行,! 另一重要的是处理时间。 我们选择的任务要花费20秒钟以上的时间,因此差异更容易发现,并且不受外部因素的影响。

下一步是什么?

原始结果可在此处获得 ,代码在GitHub上 。 请随时修改它,并让我们知道您得到什么样的结果。 如果您对我们错过的结果有更多有趣的见解或解释,我们很乐意阅读并添加到帖子中。

翻译自: https://www.javacodegeeks.com/2015/01/forkjoin-framework-vs-parallel-streams-vs-executorservice-the-ultimate-forkjoin-benchmark.html

fork join框架

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

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

相关文章

scanf在c语言中的作用是什么?

scanf()函数scanf()是C语言中的一个输入函数。与printf函数一样,都被声明在头文件stdio.h里,因此在使用scanf函数时要加上#include 。(在有一些实现中,printf函数与scanf函数在使用时可以不使用预编译命令#include 。)…

hive kerberos java_Kerberos身份验证错误 - Sqoop通过Hive从SQL导入HDFS

我给出了以下Sqoop命令:sqoop import \--connect "jdbc:sqlserver://ServerName:1433;databaseNameTESTDB;integratedSecuritytrue" \--driver com.microsoft.sqlserver.jdbc.SQLServerDriver \--table dbo.test_table \--username hduser \-P \--hive-im…

amqp rabbitmq_通过Spring Integration和RabbitMQ获得高可用性的AMQP支持的消息通道

amqp rabbitmqSpring Integration消息通道默认情况下将消息存储在内存中。 这是因为内存速度快,易于实现,并且不会增加网络成本。 但是,在某些情况下,这可能会引起问题,因为如果应用程序崩溃或服务器意外关闭&#xff…

java fx choicebox_JavaFX:具有图像和文本的ChoiceBox

我想用JavaFX ChoiceBox创建一个下拉菜单,其中每个条目都包含一个不同的图标,旁边是一个短文本. (例如,在语言选择器中,左侧有一个小标志,右侧有该语言的名称.)做这个的最好方式是什么?我试图通过CSS做到这一点.以下内容几乎可以使用,但是当然它将为所有条目设置相同…

虚函数和纯虚函数的区别是什么?

虚函数(impure virtual)  C 的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现。  子类可以重写父类的虚函数实现子类的特殊化。  如下就是一个父类中的虚函数:class A{public: virtual void ss(…

java 动态读取配置文件_java读取配置文件的几种方法

java读取配置文件的几种方法在现实工作中,我们常常需要保存一些系统配置信息,大家一般都会选择配置文件来完成,本文根据笔者工作中用到的读取配置文件的方法小小总结一下,主要叙述的是spring读取配置文件的方法。一.读取xml配置文…

java 编译 器 ide_Java 8发布一年后,IDE和编译器尚未完全就绪

java 编译 器 ide一年前, 2014年3月18日 ,发布了Java SE 8,并通过lambda表达式和streams API带来了功能性编程的幸福。 这对于我们所有的Java生态系统都是个好消息,许多人已经升级到Java8。Stack Overflow已经提出了将近2500个有关…

windows.h有哪些函数

C语言windows.h库的常用函数1:FindWindow函数该函数可以通过窗口类名或者窗口标题名来查找特定窗口句柄,返回值是窗口的句柄(在Windows中,句柄是一个系统内部数据结构的引用。例如当你操作一个窗口,或说是一个Delphi窗…

yxcms安装环境php,Windows7下PHP开发环境安装配置图文方法

操作系统:Windows 7 UltimateWEB服务器:IIS 6.1(内部版本7600)。数据库:MySql5.0.67PHP版本:5.2.13我还担心Win7下可能会不兼容,结果是一点问题都没有。一、安装MySql数据库客户端工具Navicat(导航猫)在这里下载&#…

apache camel_您的Apache Camel应用程序现在包括现成的文档

apache camel几个月前,我在博客中发布了有关即将发布的2.15版本的功能,该功能包括获取有关在端点上配置的每个属性的详细信息的功能-Apache Camel,请向我解释这些端点选项的含义 。 我们继续沿着这条道路前进,今天我们将其从端点…

C语言的三种基本程序结构是什么

一、顺序结构表达式语句、空语句、函数调用语句、复合语句程序举例&#xff1a;从键盘输入一个大写字母&#xff0c;要求改用小写字母输出。#includeint main(){ char x,y; scanf("%c",&x); if(x > A && x < Z) { …

php gd png透明,调整PNG大小并将其放在PHP / GD中较大的透明背景上?

所以&#xff0c;一切工作正常。我已经调整了源PNG大小并正确定位在创建的背景上&#xff0c;但PNG外部的其他区域变黑。我已经通过使用imagecolortransparent使它变得透明&#xff0c;但是这使png边缘变得光滑。这是我目前正在制作PNG周围的黑色条纹。请记住&#xff0c;我只在…

Hibernate锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作

介绍 Java Persistence API带有完善的并发控制机制&#xff0c;支持隐式和显式锁定。 隐式锁定机制很简单&#xff0c;它依赖于&#xff1a; 乐观锁定&#xff1a;实体状态更改可以触发版本增加 行级锁定&#xff1a;基于当前运行的事务隔离级别 &#xff0c;INSERT / UPDATE…

C语言中的指针有什么作用

C语言中的指针的作用是&#xff1a;通过指针不仅可以对数据本身&#xff0c;还可以对存储数据的变量地址进行操作。指针就是内存地址&#xff0c;指针变量是用来存放内存地址的变量。指针定义&#xff1a;指针&#xff0c;是C语言中的一个重要概念及其特点&#xff0c;也是掌握…

rsa php openssl,openssl rsa 使用简介

openssl命令的用法密钥的生成a. 生成非对称密钥对openssl genrsa -out rsa.keyb. 指定生成的密钥的位数,默认512openssl genrsa -out rsa_2048.key 2048c. 为私钥添加密码 (一般都不用)openssl genrsa -out rsa_des3.key -des3密钥的查看d. 查看私钥openssl rsa -in rsa.keye. …

docker 绑定宿主_将WildFly绑定到其他IP地址或多宿主上的所有地址

docker 绑定宿主用WildFly的话来说&#xff0c; 接口是一个逻辑名称&#xff0c;用于套接字可以绑定到的网络接口/ IP地址/主机名。 有两个接口&#xff1a;“公共”和“管理”。 “公共”接口绑定用于所有与应用程序相关的网络通信&#xff08;例如&#xff0c;Web&#xff0…

C语言标识符有哪三类

C语言标识符有关键字、用户标识符、预定义标识符三类。C语言规定&#xff0c;标识符只能由字母、数字和下划线组成&#xff0c;并且第一个字符必须是字母或下划线&#xff0c;不能是数字。C语言中的标识符可分为关键字、用户标识符、预定义标识符三类。C语言规定&#xff0c;标…

php system 执行失败,PHP 执行 system、exec 等函数发生错误

2012-12-06 20:451932人阅读评论(0)往往在调用system、exec 等函数时&#xff0c;要么没有反应&#xff0c;要么出错&#xff1a;原因很多&#xff0c;以下是抄别人的&#xff1a;错误分析&#xff1a;1、Warning: system() has been disabled for security reasons该错误是由于…

Hibernate锁定模式– PESSIMISTIC_FORCE_INCREMENT锁定模式如何工作

介绍 在上 一篇 文章中 &#xff0c;我介绍了OPTIMISTIC_FORCE_INCREMENT锁定模式&#xff0c;并将其应用于将子实体版本更改传播到锁定的父实体。 在本文中&#xff0c;我将介绍PESSIMISTIC_FORCE_INCREMENT锁定模式&#xff0c;并将其与乐观的锁定模式进行比较。 相像多于不…

C语言中字符串的结束标志是什么

C语言中字符串的结束标志是【\0】。C语言中没有专门的字符串变量&#xff0c;通常用一个字符数组来存放一个字符串&#xff0c;字符串总是以【\0】作为结束符。\0就是8位的00000000&#xff0c;因为字符类型中并没有对应的这个字符&#xff0c;所以这么写。\0就是 字符串结束标…