欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何高效的计算1~1000000000之和

程序员文章站 2022-07-10 19:13:15
简单的来算,我们可以采用 for while 之类循环来计算,下面采用的for循环 static void forSum(){ long start = System.currentTimeMillis(); long sum = 0; for (long i = 0; i <= 10_0000_0000; i++) { sum+=i; } long end = System.currentT...

简单的来算,我们可以采用 for while 之类循环来计算,下面采用的for循环

 static void forSum(){
        long start = System.currentTimeMillis();
        long sum = 0;
        for (long i = 0; i <= 10_0000_0000; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("for求和="+sum+",所花时间为:"+(end-start));
    }

我们可以想想怎么才能更有效率,for是单个线程也即是主线程在执行计算,如果多个线程同时执行计算呢?速度会不会快些,试试

static void poolSum(){
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
        ForkJoinTask<Long> submit = forkJoinPool.submit(new SumTask(0L, 10_0000_0000L));
        try {
            long sum = submit.get();
            long end = System.currentTimeMillis();
            System.out.println("ForkJoinPool求和="+sum+",所花时间为:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
static class SumTask extends RecursiveTask<Long> {
        private static final int THRESHOLD = 50_0000;//阈值
        long start;
        long end;

        public SumTask(long start, long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            long sum = 0;
            //当end与start之间的差小于threshold时,开始进行实际的累加
            if (end - start < THRESHOLD) {
                for (long i = start; i <= end; i++) {
                    sum += i;
                }
                return sum;
            } else {//当end与start之间的差大于threshold,即要累加的数超过threshold个的时候,将大任务分解成小任务
                long middle = (start + end) / 2;
                SumTask left = new SumTask(start, middle);
                SumTask right = new SumTask(middle+1, end);
                //并行执行两个小任务
                left.fork();
                right.fork();
                //把两个小任务累加的结果合并起来
                return left.join() + right.join();
            }
        }
    }


既然多个线程可以,那么多个流并行计算,是不是也可以呢?

    static void streamSum(){
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(0, 10_0000_0000).parallel().reduce(0,Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("streamSum求和="+sum+",所花时间为:"+(end-start));
    }

运行试试,看看执行的效率怎样?
如何高效的计算1~1000000000之和
我们发现好像使用并行流要快一些,其次是多线程,最后是单个线程,那么一定是这样的吗?不急,往下看

我把 THRESHOLD = 50_0000;改动了一下,如下:

static class SumTask extends RecursiveTask<Long> {
 private static final int THRESHOLD = 500;//阈值

在运行试试:
如何高效的计算1~1000000000之和
发现多线程计算时间变长了,其实这个和阈值有关,我们可以这样想,一个线程池的线程数是不是有限的,我们一直递归下去,不断创建线程,当多出了池子里的线程数,执行的时候就会有线程在等待的,而且,这还和 ForkJoinPool 的工作特点(工作窃取)有关。比如一个工作队列在执行任务,还剩最后一个任务,此时其他的线程来抢任务,就会出现短暂的等待状态。

有兴趣的小伙伴可以去了解一下

本文地址:https://blog.csdn.net/qq_42224683/article/details/107405623

相关标签: 从有发到无发