论文翻译 | 【深入挖掘Java技术】「底层原理专题」深入分析一下并发编程之父Doug Lea的纽约州立大学的ForkJoin框架的本质和原理

本文主要是介绍论文翻译 | 【深入挖掘Java技术】「底层原理专题」深入分析一下并发编程之父Doug Lea的纽约州立大学的ForkJoin框架的本质和原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

深入分析一下并发编程之父Doug Lea的纽约州立大学的ForkJoin框架的本质和原理这里写目录标题

  • 前提介绍
  • 摘要
  • 引言
  • 设计
    • 性能优秀
    • 任务粒度合理
    • Cilk框架和基础
    • fork/join的可移植性
    • FJTask框架
      • 设计思路
        • 线程映射关系
        • 拆分子任务
        • 排队及调度
        • 设置调度管理
    • 标准示例
  • 未完待续

前提介绍

Doug Lea在州立大学奥斯威戈分校(Doug Lea)

摘要

本文深入探讨了一个Java框架的设计、实现及其性能。该框架遵循并行编程的理念,通过递归方式将问题分解为多个子任务,并利用工作窃取技术进行并行处理。所有子任务完成后,其结果被整合以形成完整的并行程序。

在总体设计上,该框架借鉴了Cilk工作窃取框架的核心理念。其核心技术主要聚焦于高效的任务队列构建和管理,以及工作线程的管理。经过实际性能测试,我们发现大多数程序的并行加速效果显著,但仍有优化空间,未来可能需要进一步研究改进方案。


引言

Fork/Join并行是一种简单而高效的设计技术。它的算法思想是分而治之算法的并行版本,其典型形式包括:首先将问题分解为两个或更多的子问题,然后对每个子问题进行独立求解,最后将各个子问题的解合并以形成最终的解决方案。

Result solve(Problem problem) {if (problem is small) directly solve problemelse {split problem into independent partsfork new subtasks to solve each partjoin all subtaskscompose result from subresults}
}
  • fork操作会启动一个新的并行fork/join子任务。
  • join连接操作会导致当前任务不继续执行,直到子任务完成。

fork/join算法与其他一样,fork/join算法几乎总是递归的、反复拆分子任务,直到它们小到可以用简单、简短的顺序方法解决为止。使用简单、简短的顺序方法。

FJTask是支持这种编程风格的JavaTM框架。FJTask 作为java.util.concurrent包的一部分,可从 http://gee.cs.oswego.edu 获取。

设计

任何支持构建并行执行的子任务的框架来运行fork/join程序。支持构建并行执行的子任务、的框架运行。

不过,java.lang.Thread类(以及 POSIX pthreads 通常是 Java 线程的基础)不是支持 fork/join 程序的最优的工具。

性能优秀

fork/join任务的同步和管理要求相对简单和有规律。其产生的计算图允许采用不同于通用线程所需的调度策略。例如,除了等待子任务外,fork/join 任务从不需要阻塞。因此,通用线程的阻塞状态跟踪被视为一种资源浪费。

此外,fork/join 框架还可以利用工作窃取技术,将任务从繁忙的线程转移到空闲线程,进一步优化并行处理。

任务粒度合理

在基本任务粒度合理的情况下,构建和管理线程的成本可能高于任务本身的计算时间。虽然粒度可以在特定平台上运行程序时进行调整,但极粗粒度会限制利用并行性的机会。

简而言之,标准的线程框架过于复杂,无法满足大多数分叉/连接程序的需求。然而,线程作为其他类型并行和并行编程方式的基础,要仅仅为了支持这种编程风格而消除其开销或调整线程本身的调度是不可能的,或者至少是不切实际的。

Cilk框架和基础

虽然这些想法肯定有更长的历史,但第一个为这些问题提供系统解决方案的编程框架是Cilk。Cilk和其他轻量级可执行框架是在操作系统的基本线程或进程机制之上的特殊目的的框架,支持fork/join。

fork/join的可移植性

这种策略同样适用于Java,尽管Java线程又依赖于更低级别的操作系统功能。创建这样一个Java轻量级执行框架的主要优点是允许fork/join程序以更可移植的方式编写,并在各种支持JVM的系统上运行。

FJTask框架

FJTask框架是基于Cilk中使用的设 计的一个变体。其他变体存在于 Hood, Filaments,stackthreads,以及一些相关的轻量级系统中。

class ATask extends FJTask {public void run() {split...fork...join...compose...}
}

可执行任务。所有这些框架都将任务映射到线程,其方式与操作系统将线程映射到CPU相同,但在执行映射时,fork/join框架利用了fork/join程序的简单性、规律性和约束。虽然所有这些框架都可以适应(在不同程度上)以不同风格编写的并行程序,但它们针对fork/join设计进行了优化。

设计思路

线程映射关系

已经建立了一个工作线程池。每个工作线程都是一个标准的(“重的”)线程(这里是线程子类FJTaskRunner的一个实例),它负责处理队列中保存的任务。通常,系统上的工作线程数量和CPU核心数一样多。在Cilk等本地框架中,这些线程被映射到内核线程或轻量级进程,然后再映射到CPU。

在Java中,必须信任JVM和OS才能将这些线程映射到CPU。然而,对于操作系统来说,这是一个相对简单的任务,因为这些线程是计算密集型的。任何合理的映射策略都会将这些线程映射到不同的CPU核心上。

拆分子任务

在FJTask框架中,所有的fork/join任务都是轻量级可执行类的实例,而不是线程的实例。这些任务子类化FJTask,而不是线程,因为独立的可执行任务需要实现接口Runnable并定义一个run方法。

此外,这些任务都实现了Runnable接口,这使得它们可以作为正在执行的任务或线程的一部分交替运行。由于任务在FJTask方法支持的受限制的规则下操作,因此对FJTask进行子类化更加方便,以便能够直接调用它们。

排队及调度

在特殊目的的排队和调度规则下,任务通过工作线程得以执行和管理。这些机制通过任务类中的方法触发,主要包括fork、join、完成状态指示器isDone,以及一些实用的方法,如coInvoke,即分叉并随后连接两个或多个任务。

设置调度管理

一个简单的控制和管理工具(这里是FJTaskRunnerGroup)在从普通线程(如在Java程序中执行主任务的线程)调用时,设置工作池并启动给定的分叉/连接任务的执行。

标准示例

作为程序员如何看待这个框架的标准示例,这里是一个计算斐波那契函数的类。

 static final int threshold = 13; volatile int number; // arg/resultFib(int n) { number = n; }int getAnswer() {if (!isDone()) throw new IllegalStateException();return number;}public void run() {int n = number;if (n <= threshold) // granularity ctlnumber = seqFib(n);else {Fib f1 = new Fib(n − 1);Fib f2 = new Fib(n − 2);coInvoke(f1, f2); number = f1.number + f2.number;}}public static void main(String[] args) {try {int groupSize = 2; // for example FJTaskRunnerGroup group = new FJTaskRunnerGroup(groupSize);Fib f = new Fib(35); // for examplegroup.invoke(f);int result = f.getAnswer();System.out.println("Answer: " +result);}catch (InterruptedException ex) {} }int seqFib(int n) {if (n <= 1) return n;else return seqFib(n−1) + seqFib(n−2);}
}

这个版本的运行速度至少比在一个新的java.lang中运行的同等程序快30倍。它在维护多线程Java程序的内在可移植性的同时也做到了这一点。程序员典型感兴趣的调优参数:

  • 在构建工作线程时,其数量通常应与平台上的可用CPU数量相匹配(或更少,以保留处理用于其他非相关目的),有时甚至可能更多,以吸收非计算任务。

  • 一个粒度参数用于确定何时生成任务的成本超过了潜在的并行性带来的好处。这个参数更多地依赖于算法本身,而不是平台。通常,我们可以设定一个阈值,当在单处理器上运行时能获得良好的结果,但当存在多个CPU时仍能充分利用它们。这种方法的好处在于它与JVM的动态编译机制相契合,能够更优化地处理小方法。此外,数据局部性的优势也使得fork/join算法在某些情况下优于其他类型的算法。

未完待续

本节内容,给大家带来了对应的fork/join框架的前世今生,以及基于框架的fork和join机制的论文介绍,后续接下来会给大家带来对应的【线程盗取篇章】:论文翻译 | 【深入挖掘Java技术】「底层原理专题」深入分析一下并发编程之父Doug Lea的纽约州立大学的ForkJoin框架的本质和原理(线程盗取)

这篇关于论文翻译 | 【深入挖掘Java技术】「底层原理专题」深入分析一下并发编程之父Doug Lea的纽约州立大学的ForkJoin框架的本质和原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/602923

相关文章

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(