工作纪实45-记一段多线程批处理的代码

数据很多,多线程分批处理

@Slf4j
public class ThreadPoolUtils {
	public static <R> List<R> batchExecute(String taskName, List<?> originList, Function<List<?>, Callable<R>> supplier) {
        // 多线程批处理
        int batchSize = ContentFeedpostConfig.batchZPCreativeLimit;
        List<? extends List<?>> partition = Lists.partition(originList, batchSize);
        CompletionService<R> completionService = new ExecutorCompletionService<>(ThreadPoolUtils.getPreparePoolExecutor());
        List<Future<R>> futureList = Lists.newArrayListWithCapacity(4);
        for (List<?> list : partition) {
            Callable<R> apply = supplier.apply(list);
            futureList.add(completionService.submit(apply));
        }
        List<R> result = Lists.newArrayListWithCapacity(4);
        for (int n = 0; n < futureList.size(); n++) {
            try {
                Future<R> future = completionService.poll(10, TimeUnit.MILLISECONDS);
                if (future != null) {
                    R r = future.get();
                    if (r != null) {
                        result.add(r);
                    }
                }
            } catch (TimeoutException overtime) {
                MetricUtils.EXCEPTION_COUNTER.labels(taskName).inc();
                if (EXCEPTION_LOG_RATE_LIMITER.tryAcquire()) {
                    log.error("{} timeout exception ", taskName, overtime);
                }
            } catch (Exception e) {
                if (e instanceof InterruptedException) {
                    Thread.currentThread().interrupt();
                }
                MetricUtils.EXCEPTION_COUNTER.labels(taskName).inc();
                if (EXCEPTION_LOG_RATE_LIMITER.tryAcquire()) {
                    log.error("{} unknown exception ", taskName, e);
                }
            }
        }
        return result;
    }
}

public static Table<Long, String, Object> queryZhaoPinExplain(Map<String, String> firstRequest, List<Info> infoList) {
        // 参数预处理
        DispLocal dispLocal = ParamsUtils.getZhaoPinUserLocal(firstRequest);
        DispCategory dispCategory = ParamsUtils.getZhaoPinCate();
        // 多线程批处理
        List<ExplanationResult> batchExecuteResult = ThreadPoolUtils.batchExecute("queryZhaoPinExplain", infoList, list -> {
            List<ExplanationJob> jobList = Lists.newArrayListWithCapacity(list.size());
            list.forEach(info -> {
                ExplanationJob job = new ExplanationJob();
                job.setInfo((Info) info);
                jobList.add(job);
            });
            ParamInfo paramInfo = new ParamInfo();
            paramInfo.setSlot("appindex_joblist");// 首页是固定的,如果有其他场景需要适配,需要通知招聘业务线进行开发
            paramInfo.setSid(firstRequest.getOrDefault("fid", ""));
            paramInfo.setUserid(firstRequest.getOrDefault("userid", ""));
            paramInfo.setPlatform(3);// app
            paramInfo.setIp(firstRequest.getOrDefault("clientIp", ""));// 客户端id
            paramInfo.setImei(firstRequest.getOrDefault("imei", ""));
            paramInfo.setParams("{\"personPri\":\"P1\"}");
            paramInfo.setDisplocal(dispLocal);
            paramInfo.setDispcate(dispCategory);
            return () -> explainService.getExplanationResult(jobList, paramInfo);
        });
        // 返回值处理
        Table<Long, String, Object> result = HashBasedTable.create();
        for (ExplanationResult scfReturn : batchExecuteResult) {
            List<ExplanationInfo> explanationResult = scfReturn.getExplanationInfos();
            // 获取标题、标签、推荐理由
            explanationResult.forEach(k -> {
                long infoID = k.getInfoID();
                ExplanationSchema title = k.getExplanationSchemaFromDomain(ExplanationInfoDomainEnum.TITLE);
                if (!title.isWithMultipleValues()) {
                    result.put(infoID, "title", title.getText());
                }
                ExplanationSchema label = k.getExplanationSchemaFromDomain(ExplanationInfoDomainEnum.LABEL);
                if (label.isWithMultipleValues()) {
                    List<String> list = label.getValues().stream().map(ExplanationSchema::getText).collect(Collectors.toList());
                    result.put(infoID, "tags", list);
                }
                ExplanationSchema reason = k.getExplanationSchemaFromDomain(ExplanationInfoDomainEnum.REASON);
                if (reason.isWithMultipleValues()) {
                    List<String> list = reason.getValues().stream().map(ExplanationSchema::getText).collect(Collectors.toList());
                    result.put(infoID, "reasons", list);
                }
            });
        }
        return result;
    }
CompletionService是一个接口,它继承自Executor接口,并为提交的任务提供了一种获取完成结果的机制。在使用CompletionService时,常用的方法包括:

submit(Callable task):将任务提交给CompletionService进行处理,并返回表示任务结果的Future对象。
submit(Runnable task, T result):将任务提交给CompletionService进行处理,并返回表示任务结果的Future对象,此处的result参数用于任务执行完成后返回的结果。
take():获取已完成的任务的结果,并返回表示任务结果的Future对象。如果没有已完成的任务,take()方法会阻塞等待任务完成。
poll():尝试立即获取已完成的任务的结果,并返回表示任务结果的Future对象。如果没有已完成的任务,poll()方法会立即返回nullpoll(long timeout, TimeUnit unit):在指定的时间内,尝试获取已完成的任务的结果,并返回表示任务结果的Future对象。如果在指定时间内没有已完成的任务,poll()方法会返回null。
这些方法提供了不同的方式来获取已完成任务的结果,take()方法会阻塞等待任务完成,而poll()方法则是立即返回结果或者null

变种代码,如果定义和结果获取需要分开的话

	public static <R> List<Future<R>> batchExecuteSubmit(int batchSize, List<?> originList, Function<List<?>, Callable<R>> supplier, CompletionService<R> completionService) {
        // 多线程批处理
        List<? extends List<?>> partition = Lists.partition(originList, batchSize);
        List<Future<R>> futureList = Lists.newArrayListWithCapacity(4);
        for (List<?> list : partition) {
            Callable<R> apply = supplier.apply(list);
            futureList.add(completionService.submit(apply));
        }
        return futureList;
    }

    public static <R> List<R> batchExecutePost(String taskName, List<Future<R>> futureList, CompletionService<R> completionService){
        List<R> result = Lists.newArrayListWithCapacity(4);
        for (int n = 0; n < futureList.size(); n++) {
            try {
                Future<R> future = completionService.poll(timeout, TimeUnit.MILLISECONDS);
                if (future != null) {
                    R r = future.get();
                    if (r != null) {
                        result.add(r);
                    }
                }
            } catch (Exception e) {
                if (e instanceof InterruptedException) {
                    Thread.currentThread().interrupt();
                }
                MetricUtils.EXCEPTION_COUNTER.labels(taskName).inc();
                if (EXCEPTION_LOG_RATE_LIMITER.tryAcquire()) {
                    log.error("{} unknown exception ", taskName, e);
                }
            }
        }
        return result;
    }
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值