forkjoin并行框架实践

博客指出,查询SQL时发起请求后需等待数据库返回,属IO密集型操作,线程数可粗略设为2*N(N为CPU核心数)或(总时间/cpu时间)*N;对于CPU密集型任务,线程数设置为N+1即可,过多会因上下文切换浪费时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 @Override
    public List<TaxForeDTO> getTaxForeForkJoin(List<String> organizeId, String uid, Date Begin, Date end)
            throws Exception {
        Long begintime=System.currentTimeMillis();
        //cpu+io总耗时23秒 io时间21秒
        //最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目
        //21/2+1
        int nums= 11*Runtime.getRuntime().availableProcessors();
        log.info("线程数{}",organizeId.size());
      //  ForkJoinPool forkjoinPool = new ForkJoinPool(nums);
        ForkJoinPool forkjoinPool = new ForkJoinPool(organizeId.size());
        //生成一个计算任务
        ForkJoinTaskExample task = new ForkJoinTaskExample(organizeId, uid,Begin,end);

        //执行一个任务
        Future<List<TaxForeDTO>> result = forkjoinPool.submit(task);

        List<TaxForeDTO> list=new ArrayList<>();
        try {
            list=result.get();
            log.info("result:{}", list);
        } catch (Exception e) {
            log.error("exception", e);
        }

        Long endtime=System.currentTimeMillis();
        log.info("预测表并行开始时间{},结束时间{},总耗时{},秒数{}", begintime,endtime, endtime-begintime,(endtime-begintime)/1000.0f);
        return list;
    }

     class ForkJoinTaskExample extends RecursiveTask<List<TaxForeDTO>> {

        public  final int threshold = 2;

        private List<String> organizeId;
        private String uid;
        private  Date Begin;
        private Date endDate;
        private int start;
        private int end;

        public ForkJoinTaskExample(List<String> organizeId, String uid, Date begin, Date end) {
            this.organizeId = organizeId;
            this.uid = uid;
            this.Begin = begin;
            this.endDate = end;
            this.start=0;
            this.end=organizeId.size()-1;

        }

        @Override
        protected List<TaxForeDTO> compute() {
            List<TaxForeDTO> sum=new ArrayList<>();
            //如果任务足够小就计算任务
            boolean canCompute = (end - start) <=threshold;
            if (canCompute) {
                try {
                    sum.addAll(getTaxFore(organizeId.subList(start,end),uid,Begin,endDate));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                // 如果任务大于阈值,就分裂成两个子任务计算
                int middle = (start + end) / 2;
                ForkJoinTaskExample leftTask = new ForkJoinTaskExample(organizeId.subList(start,middle),uid,Begin,endDate);
                ForkJoinTaskExample rightTask = new ForkJoinTaskExample(organizeId.subList(middle+1,end),uid,Begin,endDate);

                // 执行子任务
                leftTask.fork();
                rightTask.fork();

                // 等待任务执行结束合并其结果
                List<TaxForeDTO>  leftResult = leftTask.join();
                List<TaxForeDTO>  rightResult = rightTask.join();

                // 合并子任务
                sum.addAll(leftResult);
                sum.addAll(rightResult);
            }
            return sum;
        }
    }

这里注意下 ,想查询sql这种,因为发起请求之后 要等待数据库的返回,大部分时间其实是在等待io。 这种频繁等待io的操作 是io密集型,这个时候设置的线程数
可以粗略的设置成2*N (N为cpu核心数 可以用Runtime.getRuntime().availableProcessors() 获取) ,或者设置成(总时间/cpu时间)*N 总时间是指cpu时间+等待io时间

如果是cpu密集型任务,则线程数设置为N+1就差不多了,再多 也会因为上下文切换而浪费时间,而且 cpu也不堪重负。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值