首页 > 其他分享 >【揭秘】RecursiveAction全面解析

【揭秘】RecursiveAction全面解析

时间:2024-01-29 19:00:55浏览次数:17  
标签:elements int Sum RecursiveAction 任务 array 解析 揭秘

【揭秘】RecursiveAction全面解析 - 程序员古德

内容概要

RecursiveAction是Java中一个强大的工具,它允许将复杂任务分解为更小的子任务,这些子任务可以并行执行,从而提高整体性能,其主要优点在于能够有效地利用多核处理器,减少任务执行时间,并简化并行编程的复杂性。

核心概念

RecursiveAction 是 Java 并发包 java.util.concurrent 中的一个类,它继承自ForkJoinTask,它主要用于解决可以递归分解为更小独立任务的问题,并且这些子任务可以并行执行以优化性能,它不返回结果(与 RecursiveTask 相对,后者返回结果)。

当面对一个需要将任务分解为多个独立部分的问题时,非常合适使用 RecursiveAction ,通常它用于解决具有以下特点的问题:

  1. 可分解性:大问题可以递归地分解为更小的子问题,直到这些子问题变得足够小,可以直接解决而无需进一步分解。
  2. 无返回值:处理过程不需要聚合子任务的结果,如果需要结果,通常会使用 RecursiveTask
  3. 并行性:子任务之间相互独立,可以并行执行以提高效率。

典型的应用场景包括:

  • 并行遍历和处理数据结构:如:遍历一个大型数组或列表,并对每个元素执行某种操作,可以将数组分成几个部分,然后并行处理每个部分。
  • 分治算法:如,快速排序、归并排序等,这些算法天然地适合使用 RecursiveAction 进行并行化。
  • 图像处理:如,将大型图像分割成多个小块,并行地对每个小块进行处理。
  • 任何可并行化的批处理任务:如发送批量电子邮件、并行下载文件等。

注意:使用 RecursiveAction 的关键是正确实现 compute 方法,以定义如何分解任务和执行子任务,通过 ForkJoinPool 执行 RecursiveAction,可以自动管理任务的分解、执行和结果合并。

代码案例

如下是一个RecursiveAction的简单示例,在这个示例中,将实现一个计算数组元素之和的任务,该任务可以被递归地分解为更小的子任务。

先定义一个继承自RecursiveAction的类ArraySumAction,它计算数组的一部分元素之和,并且可以递归地分解任务,如下代码:

import java.util.concurrent.RecursiveAction;  
  
public class ArraySumAction extends RecursiveAction {  
  
    private static final int THRESHOLD = 100; // 任务分解的阈值  
    private final int[] array;  
    private final int start;  
    private final int end;  
  
    public ArraySumAction(int[] array, int start, int end) {  
        this.array = array;  
        this.start = start;  
        this.end = end;  
    }  
  
    @Override  
    protected void compute() {  
        if (end - start < THRESHOLD) {  
            // 任务足够小,直接计算  
            int sum = 0;  
            for (int i = start; i < end; i++) {  
                sum += array[i];  
            }  
            System.out.println("Sum of elements " + start + " to " + (end - 1) + " is " + sum);  
        } else {  
            // 任务太大,分解为子任务  
            int mid = start + (end - start) / 2;  
            ArraySumAction leftAction = new ArraySumAction(array, start, mid);  
            ArraySumAction rightAction = new ArraySumAction(array, mid, end);  
  
            // 递归执行子任务  
            leftAction.fork();  
            rightAction.fork();  
        }  
    }  
}

然后是client代码,并提交任务以进行计算,如下代码:

import java.util.concurrent.ForkJoinPool;  
  
public class RecursiveActionExample {  
  
    public static void main(String[] args) {  
        int[] array = new int[1000];  
  
        // 初始化数组  
        for (int i = 0; i < array.length; i++) {  
            array[i] = i;  
        }  
  
        // 创建ForkJoinPool  
        ForkJoinPool pool = new ForkJoinPool();  
  
        // 提交任务  
        pool.invoke(new ArraySumAction(array, 0, array.length));  
  
        // 注意:这里使用了invoke而不是execute,因为invoke会等待任务完成  
        // 而execute则不会。在这个例子中,希望等待所有子任务完成后再退出程序。  
  
        System.out.println("All tasks are completed.");  
  
        // 关闭ForkJoinPool(在实际应用中可能需要这样做,但在这个简单示例中不是必须的)  
        pool.shutdown();  
    }  
}

在上面的代码示例中,ArraySumAction类将数组分成两部分,直到每部分的大小小于预设的阈值(在这里是100),当任务足够小时,它将直接计算结果并打印出来,client代码创建了一个包含1000个元素的数组,并使用ForkJoinPool来执行ArraySumAction任务。

运行代码出现如下结果:

Sum of elements 0 to 99 is 4950  
Sum of elements 500 to 599 is 249500  
Sum of elements 200 to 299 is 249000  
Sum of elements 700 to 799 is 524000  
Sum of elements 400 to 499 is 499000  
Sum of elements 100 to 199 is 249500  
Sum of elements 300 to 399 is 499500  
Sum of elements 600 to 699 is 748500  
Sum of elements 800 to 899 is 1048500  
Sum of elements 900 to 999 is 1249500  
All tasks are completed.

核心总结

【揭秘】ForkJoinTask全面解析 - 程序员古德

当遇到那些可分解为更小、独立子任务的问题时,非常适合使用RecursiveAction,它通过将大任务分而治之,能显著提高处理大数据集的速度,尤其是当这些子任务之间几乎不存在通信或同步时,它的效率最高。

使用RecursiveAction的最大优势是能够充分利用多核处理器,从而加快处理速度。但是需要注意,如果子任务之间存在大量的通信或依赖,那么就不是非常适合使用RecursiveAction。

关注我,每天学习互联网编程技术 - 程序员古德

标签:elements,int,Sum,RecursiveAction,任务,array,解析,揭秘
From: https://blog.51cto.com/bytegood/9446260

相关文章

  • C++ Qt开发:运用QJSON模块解析数据
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析功能。JSON(JavaScriptObjectNotation)是一种轻量级......
  • 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构
    英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构技术和性能对比带你解决疑惑近期,AIGC领域呈现出一片繁荣景象,其背后离不开强大算力的支持。以ChatGPT为例,其高效的运行依赖于一台由微软投资建造的超级计算机。这台超级计算机配备了数万个NVIDIA......
  • 无涯教程-Swift - 解析构造
    在需要释放一个类实例之前,必须调用"deinitializer"来释放内存空间,关键字"deinit"用于取消分配系统资源占用的内存空间。释放内存空间当不再需要实例时,Swift4会自动释放其实例,以释放资源。Swift4通过自动引用计数(ARC)处理实例的内存管理,如自动引用计数中所述。通常,在实例......
  • 英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构
    英伟达系列显卡大解析B100、H200、L40S、A100、A800、H100、H800、V100如何选择,含架构技术和性能对比带你解决疑惑近期,AIGC领域呈现出一片繁荣景象,其背后离不开强大算力的支持。以ChatGPT为例,其高效的运行依赖于一台由微软投资建造的超级计算机。这台超级计算机配备了数万个NVIDI......
  • Kotlin扩展函数原理解析
    一、扩展函数扩展函数可以方便地给现有类增加属性和方法而不改动类地代码。二、原理funString.addTo(s:String):String{returnthis+s}反编译:@Metadata(mv={1,6,0},k=2,d1={"\u0000\n\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u......
  • 【SpringBoot】当AOP引发的异常与@RestControllerAdvice擦肩而过:异常处理的盲点揭秘
    各位上午/下午/晚上好呀!今天在写bug的时候发现一个这样的问题:AOP抛出的异常竟然没有被@RestControllerAdvice注解修饰的异常统一处理类处理。 需求是这样子滴:对某些加了自定义注解的方法进行切面处理,通过条件判断是否有权限执行该方法。伪代码大概长这个样子:@Around(......
  • 揭秘亚马逊鲲鹏系统:打造独立账号环境,实现多账号管理
    在当今繁忙的电商运营中,多账号管理而不被关联是许多卖家追求的目标。为了实现这一目标,防指纹软件成为了必不可少的利器。其中,基于防指纹浏览器开发的全自动操作软件——亚马逊鲲鹏系统,成为了众多卖家的首选,其功能之齐全令人称道。亚马逊鲲鹏系统不仅可以批量注册亚马逊买家号,还能自......
  • 名企测试管理大咖解析沟通管理,多维度经验分享
    沟通管理在测试开发中扮演着至关重要的角色,它不仅是团队协作的基石,也是项目成功的关键因素之一。有效的沟通管理能够促进信息传递、问题解决以及团队协同工作,为测试开发的顺利进行提供坚实支持。但在实际工作中却有很多的问题,你是否在工作中遇到过以下问题呢?在团队会议上,需要分享自......
  • [转]TypeScript类型编程中的extends和infer示例解析
    转自;https://www.jb51.net/javascript/294261vgi.htm TypeScript类型编程中的extends和infer示例解析 −目录引文extends条件判断约束参数类型约束infer推导的局部变量类型类型转换infer组合使用ReturnTypeParameters引文在刚接触TypeScript的时候,......
  • java读取并解析XML文件的方法有哪些?
    XMLStreamReader:1. DOM(DocumentObjectModel)方式:DOM将整个XML文档加载到内存中,形成一颗树状结构,然后通过操作这个树状结构来获取所需要的数据。示例代码如下:importjavax.xml.parsers.*;importorg.w3c.dom.*;publicclassXMLParser{publicstaticvoidmain(Stri......