• 【总结】ITOO在线编辑性能优化——多线程


       项目背景

               

         

    问题:

          由上图可以知道,“页面需要根据试卷id获取全部的试卷信息”,由下面代码可以看出根据返回的“returnPaperDetail”进行开始进行嵌套循环操作。
         图解:
      

           具体代码如下
         
    /**
    * 功能:queryAllQuestion
    * 描述:加载页面查询出所有表的数据
    * 主要实体:ExaminationPaper(4张表的联合:questionMain,questionSub,paperMain,paperSub)
    * 作者:十一期 谭倩倩
    * 时间:2016-6-18
    * 修改人:
    * 修改时间:
    * @param request
    * @param response
    */
    @RequestMapping("/queryAllQuestion")
    public void queryAllQuestion(HttpServletRequest request,HttpServletResponse response)
    {
    //1.抽取paperMain
    ExaminationPaper examinationPaper=new ExaminationPaper();
    String paperMainId=paperId.replace("'", "");//暂时使用假数据
    String dataBaseName="itoo_exam";
    PaperMain RepaperMain=paperMainBean.queryPaperMainById(paperMainId, dataBaseName);
    examinationPaper.setId(paperMainId);
    examinationPaper.setPaperName(RepaperMain.getComment());
    examinationPaper.setPaperScore(RepaperMain.getScore());
    //2. 抽取paperdetail和questionMain数据(嵌套循环)
    List<PaperDetail> returnPaperDetail=this.ReturnqueryPaperDetail(paperMainId, dataBaseName);
    List<QuestionMain> RequestionMainList=new ArrayList<QuestionMain>();
    List<QuestionSub> RequestionSubList=new ArrayList<QuestionSub>();
    //循环paperdetail
    for (PaperDetail returnSinglePaperDetail : returnPaperDetail)
    {
    RequestionMainList=this.ReturnQuestionMain(returnSinglePaperDetail.getId(), dataBaseName);
    RequestionMainList = orderByQuestionMainList(RequestionMainList);
    for (QuestionMain returnSinglequestionMain : RequestionMainList)
    {
    RequestionSubList=this.ReturnQuestionSub(returnSinglequestionMain.getId(), dataBaseName);
    returnSinglequestionMain.setOptions(RequestionSubList);
    }
    //查询出来的组件
    List<QuestionTypeDetail> lstQuestionTypeDetail = paperMainBean.queryComponentById(
    returnSinglePaperDetail.getQuestionTypeId(), dataBaseName);
    returnSinglePaperDetail.setLstQuestionTypeDetail(lstQuestionTypeDetail);
    //把组件的英文名称装到“returnSinglePaperDetail”里面
    returnSinglePaperDetail.setLstQuestionMain(RequestionMainList);
     
    }
    examinationPaper.setPaperDetails(returnPaperDetail);
    jacksonJson.beanToJson(response, examinationPaper);
    }
     
    /**
    * @param RequestionMainList
    * @return
    */
    private List<QuestionMain> orderByQuestionMainList(
    List<QuestionMain> RequestionMainList) {
    /**对大小题进行排序思路:
    // * ①定义一个 List<QuestionMain> bigLittleQuestion 用于存放排好序的大小题。
    // * ②判断查出来的题型是大小题,则先筛选大题。
    // * ③如果是大题,将其放到bigLittleQuestion中。
    // * 然后遍历所有题目,找到该大题对应的所有小题。放到bigLittleQuestion中。
    // *
    // *
    // */
    ………………………………………………………………
    }

    【解决方案】


            一套试卷有多个题型,那么我就设置每个题型为一个线程。

       图示:




    代码如下:
          大体是实例化一个线程池,根据题目数量的多少来添加多少个线程,一个题型代表一个线程,最后遍历线程结果。
      
    public void queryAllQuestion(HttpServletRequest request,HttpServletResponse response)
    {
    //1.抽取paperMain
    ExaminationPaper examinationPaper=new ExaminationPaper();
    String paperMainId=paperId.replace("'", "");//暂时使用假数据
    String dataBaseName="itoo_exam";
    PaperMain RepaperMain=paperMainBean.queryPaperMainById(paperMainId, dataBaseName);
    examinationPaper.setId(paperMainId);
    examinationPaper.setPaperName(RepaperMain.getComment());
    examinationPaper.setPaperScore(RepaperMain.getScore());
    //2. 抽取paperdetail和questionMain数据(嵌套循环)
    List<PaperDetail> returnPaperDetail=this.ReturnqueryPaperDetail(paperMainId, dataBaseName);
    //测试加上线程的时间
    long startTime=System.currentTimeMillis();
    int count=returnPaperDetail.size();
    //创建一个线程池
    ExecutorService executorService = Executors.newCachedThreadPool();
    List<Future<PaperDetail>> resultList = new ArrayList<Future<PaperDetail>>();
    for (PaperDetail returnSinglePaperDetail : returnPaperDetail) {
    //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
    Future<PaperDetail> future = executorService.submit(new myCallable(returnSinglePaperDetail));
    //将任务执行结果存储到List中
    resultList.add(future);
    }
    List<PaperDetail> listPapaerDeatil=new ArrayList<PaperDetail>();
    //遍历任务的结果
    for (Future<PaperDetail> fp: resultList) {
    try {
    PaperDetail enPaperDetail =fp.get();
    listPapaerDeatil.add(enPaperDetail);
    } catch (InterruptedException | ExecutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    //启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
    executorService.shutdown();
    }
    examinationPaper.setPaperDetails(listPapaerDeatil);
    long endTime=System.currentTimeMillis();
    System.out.println(endTime-startTime);
     
    jacksonJson.beanToJson(response, examinationPaper);
    }

    /**
    * 多线程进行题干和选项查询。
    * @author 十一期 谭倩倩
    *
    */
    @SuppressWarnings("unchecked")
    public class myCallable implements Callable<PaperDetail>{
    private PaperDetail paperDetail;
    public myCallable(PaperDetail paperDetail) {
    this.paperDetail = paperDetail;
    }
    String dataBaseName="itoo_exam";
    public PaperDetail call(){
    List<QuestionMain> RequestionMainList=questionMainBean.queryQuestionbankList(paperDetail.getId(), dataBaseName);
    RequestionMainList = orderByQuestionMainList(RequestionMainList);
    for (QuestionMain returnSinglequestionMain : RequestionMainList)
    {
    List<QuestionSub> RequestionSubList=questionSubBean.queryQuestionbankOptionsList(returnSinglequestionMain.getId(), dataBaseName);
    returnSinglequestionMain.setOptions(RequestionSubList);
    }
    //查询出来的组件
    List<QuestionTypeDetail> lstQuestionTypeDetail = paperMainBean.queryComponentById(
    paperDetail.getQuestionTypeId(), dataBaseName);
    paperDetail.setLstQuestionTypeDetail(lstQuestionTypeDetail);
    //把组件的英文名称装到“returnSinglePaperDetail”里面
    paperDetail.setLstQuestionMain(RequestionMainList);
    return paperDetail;
    }
    }


    【结果】

    没有用线程的结果是:
    (第一套测试卷子)


    (第二套测试卷子)



    用了线程的结果是:

    (第一套测试卷子)




    (第二套测试卷子)




    【总结】

          还需要优化的性能:

          1. 算法优化


            (需要优化的代码)
    private List<QuestionMain> orderByQuestionMainList(
    List<QuestionMain> RequestionMainList) {
    /**对大小题进行排序思路:
    // * ①定义一个 List<QuestionMain> bigLittleQuestion 用于存放排好序的大小题。
    // * ②判断查出来的题型是大小题,则先筛选大题。
    // * ③如果是大题,将其放到bigLittleQuestion中。
    // * 然后遍历所有题目,找到该大题对应的所有小题。放到bigLittleQuestion中。
    // *
    // * 仍需要优化
    // */
    if (RequestionMainList!=null && RequestionMainList.size()>1 )
    {
    if ( RequestionMainList.get(0).getIsParentQuestion()==1 || RequestionMainList.get(0).getParentQuestionId()!=null)
    {//筛选是大小题
    List<QuestionMain> bigLittleQuestion=new ArrayList<QuestionMain>();
    for (int i = 0; i < RequestionMainList.size(); i++)
    {
    if (RequestionMainList.get(i).getIsParentQuestion()==1)
    {//查找出所有的大题干
    bigLittleQuestion.add(RequestionMainList.get(i));
    //查找该大题干下面所有的小题干
    for (int j = 0; j < RequestionMainList.size(); j++)
    {
    //匹配该大题干下面的小题干
    if(RequestionMainList.get(j).getParentQuestionId()!=null)
    {
    if (RequestionMainList.get(j).getParentQuestionId().equals(RequestionMainList.get(i).getId()))
    {
    bigLittleQuestion.add(RequestionMainList.get(j));
    }
    }
    }
    }
    }
    RequestionMainList=bigLittleQuestion;
    }
    }
    return RequestionMainList;
    }

          2. 批量查询或者缓存


             (需要优化的代码)
    for (QuestionMain returnSinglequestionMain : RequestionMainList)
    {
    List<QuestionSub> RequestionSubList=questionSubBean.queryQuestionbankOptionsList(returnSinglequestionMain.getId(), dataBaseName);
  • 相关阅读:
    使用Docker搭建Wordpress
    Django开发Web页面html增加判断展示
    Python如何取小数点位数
    html内容可编写
    MySQL 设置 非空约束依然能插进去的办法
    Git拉取远程所有分支
    my.ini 配置文件
    node
    TP upload 上传根目录不存在
    linux 安装 memcache
  • 原文地址:https://www.cnblogs.com/tanqianqian/p/5975011.html
Copyright © 2020-2023  润新知