• 将List按照指定大小等分的几种实现方式和效率对比及优化


      今天碰到一个需求,定时任务,批量从表里取数据并做一些其他操作然后再存表,每次取1000条,由于计算过程比较耗时所以要起多个线程同时跑,需要将List按照指定大小等分,如每100条数据起一个线程,若最后剩余一份不到100,也放到一个线程里,网络上的实现方法有很多,我测试之后理出三种相对比较好的实现方法,如下:

     1 /*第一种方法 思路比较简单,遍历list,将元素添加到subList,
     2 *每当i到pageSize的时候,将subList添加到listArray并新建,subList
     3 */
     4 public static <T> List<List<T>> splitList1(List<T> list, int pageSize) {
     5  
     6     List<List<T>> listArray = new ArrayList<List<T>>();
     7  
     8     List<T> subList = null;
     9  
    10     for (int i = 0; i < list.size(); i++) {
    11  
    12         if (i % pageSize == 0) {
    13  
    14             subList = new ArrayList<T>();
    15  
    16             listArray.add(subList);
    17  
    18         }
    19  
    20         subList.add(list.get(i));
    21  
    22     }
    23  
    24     return listArray;
    25  
    26 }
    /*第二种方法 思路和方法1差不多,遍历list,将元素添加到subList,
    *当subList的size等于pageSize的时候,将subList添加到listArray并新建subList
    */
    public static <T> List<List<T>> splitList2(List<T> list, int pageSize) {
     
        List<List<T>> listArray = new ArrayList<List<T>>();
     
        ArrayList<T> subList = new ArrayList<T>();
        for (T x : list) {
            subList.add(x);
            if (pageSize == subList.size()) {
                listArray.add(subList);
                subList = new ArrayList<T>();
            }
        }
     
        if (0 != subList.size()) {
            listArray.add(subList);
        }
     
        return listArray;
    }
    /*第三种方法,用到了java list自带的方法subList,
    *先判断list的size<pageSize的情况,然后利用subList方法循环切块
    */
    public static <T> List<List<T>> splitList3(List<T> list, int pageSize) {
        List<List<T>> listArray = new ArrayList<List<T>>();
        if (list != null && pageSize > 0) {
            int listSize = list.size();
            if (listSize <= pageSize) {
                listArray.add(list);
                return listArray;
            }
            int batchSize = listSize / pageSize;
            int remain = listSize % pageSize;
     
            for (int i = 0; i < batchSize; i++) {
                int fromIndex = i * pageSize;
                int toIndex = fromIndex + pageSize;
                listArray.add(list.subList(fromIndex, toIndex));
            }
            if (remain > 0) {
                listArray.add(list.subList(listSize - remain, listSize));
            }
        }
        return listArray;
    }

      我从list的subList方法中得到灵感,也实现了一种方式,可读性稍好一些,如下:

    /*我的思路也比较简单,就是遍历加切块,
    *若toIndex大于list的size说明已越界,需要将toIndex设为list的size值
    */
    public static <T> List<List<T>> splitList4(List<T> list, int pageSize) {
        List<List<T>> listArray = new ArrayList<List<T>>();
        for (int i = 0; i < list.size(); i+=pageSize) {
            int toIndex = i + pageSize>list.size()?list.size():i+pageSize;
            listArray.add(list.subList(i, toIndex));
        }
        return listArray;
    }

      以上四种方法经过测试都可实现功能,如果List的size比较小,几十,几百,应该效率都差不多,那如果list的size很大,比如10万,100万,那么以上四种方式,哪一种效率最高呢,我简单测试了一下,pageSize设为20,list的size分别为10万,和100万,分别跑100次,然后取平均值,如下:

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
     
        for (int i = 0; i < 100000; i++) {
            list.add(i);
        }
     
        Long time1 = System.currentTimeMillis();
        for (int i = 0; i <100 ; i++) {
            splitList1(list, 20);
        }
        Long time2 = System.currentTimeMillis();
        for (int i = 0; i <100 ; i++) {
            splitList2(list, 20);
        }
        Long time3 = System.currentTimeMillis();
        for (int i = 0; i <100 ; i++) {
            splitList3(list, 20);
        }
        Long time4 = System.currentTimeMillis();
        for (int i = 0; i <100 ; i++) {
            splitList3(list, 20);
        }
        Long time5 = System.currentTimeMillis();
     
     
        System.out.println("list的size为10000,执行100次,平均时间为:");
        System.out.println("方法1--->:" + (time2 - time1)/100.0+"ms");
        System.out.println("方法2--->:" + (time3 - time2)/100.0+"ms");
        System.out.println("方法3--->:" + (time4 - time3)/100.0+"ms");
        System.out.println("方法4--->:" + (time5 - time4)/100.0+"ms");
     
     
    }

      执行结果为:

    list的size为100000,执行100次,平均时间为:
    方法1--->:2.86ms
    方法2--->:2.08ms
    方法3--->:0.66ms
    方法4--->:0.43ms

        从执行结果中可以看到前两种方法效率,明显不如后两种,后两种时间相差不大,但看起来似乎方法4更好一些,再将list的size设为100万时,执行结果为:

    list的size为1000000,执行100次,平均时间为:
    方法1--->:21.65ms
    方法2--->:14.09ms
    方法3--->:0.95ms
    方法4--->:0.57ms

      size设为1000万时,执行结果为:

    list的size为1000000,执行100次,平均时间为:
    方法1--->:138.39ms
    方法2--->:112.86ms
    方法3--->:6.63ms
    方法4--->:6.07ms

      综上所看,方法4的效率稍好于方法3,方法2稍好于方法1,但3和4的效率比1和2要高出一个数量级,主要是因为方法1和2,是逐个设置的,很明显不如subList,在这里推荐方法4,代码简洁,稍微理解下,可读性也不错.


    原文链接:https://www.imooc.com/article/41647
    来源:慕课网
    本文原创发布于慕课网 ,转载请注明出处,谢谢合作

  • 相关阅读:
    CDH6.3.1安装详细步骤(感写B站若泽大数据)
    windows远程ubuntu UI教程
    CentOS7搭建Tensorflow计算环境(cuda+cudnn+jupyterlab(Anaconda3)+pytorch+Tensorflow)
    中国计算机学会推荐国际学术会议和期刊目录-2019
    基于BA网络模型的二部图数据集生成
    GitHub文件的克隆与上传
    博客园中随笔,文章的区别
    Pycharm新建文件时头部模板的配置方法
    asyncio 和aiohttp
    随机UA
  • 原文地址:https://www.cnblogs.com/fingerboy/p/9279290.html
Copyright © 2020-2023  润新知