零、背景
最近在做数据迁移
为了加速迁移速度
其中就需要把查询到的数据( max 100 条)
拆分成 5 份,然后执行 5 个子任务,加速处理
一、代码
1.1 常规做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | public static <T> List<List<T>> split2(List<T> lists, int subCount) {     if (CollectionUtils.isEmpty(lists) || subCount < 1) {         return null;     }
      List<List<T>> result = new ArrayList<>();
      int size = lists.size();     int count = (size + subCount - 1) / subCount;
      for (int i = 0; i < count; i++) {         List<T> subList = lists.subList(i * subCount, (Math.min((i + 1) * subCount, size)));         result.add(subList);     }     return result; }
  | 
1.2 新颖做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | public static <T> List<List<T>> split(List<T> lists, int subCount) {     if (CollectionUtils.isEmpty(lists) || subCount < 1) {         return null;     }          int splitTimes = (lists.size() + subCount - 1) / subCount;     return Stream                          .iterate(0, n -> n + subCount)                          .limit(splitTimes)                          .map(item -> lists.stream()                                          .skip(item)                                          .limit(subCount)                                          .collect(Collectors.toList()))                          .collect(Collectors.toList()); }
  | 
三、性能
3.1 结果
从结果可以看出,一味地追求新颖也不是好事,需要知其然
Java 8 的 stream 并不占优势,性能相差好几个数量级…
1 2 3
   | Benchmark              Mode  Cnt       Score       Error  Units ListSplit.split2Test  thrpt   10  306050.155 ± 24646.689  ops/s ListSplit.splitTest   thrpt   10     353.048 ±   122.423  ops/s
   | 
3.3 压测代码
压测教程:JMH 使用参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
   | import com.google.api.client.util.Lists; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.springframework.util.CollectionUtils;
  import Java.util.ArrayList; import Java.util.List; import Java.util.stream.Collectors; import Java.util.stream.Stream;
 
 
 
 
 
  @State(Scope.Thread)
  @Fork(1)
  @Warmup(iterations = 1)
  @Measurement(iterations = 10) @BenchmarkMode(Mode.Throughput) public class ListSplit {     private static final List<Integer> INTEGERS = Lists.newArrayList();     @Setup     public void init() {         List<Integer> list = Stream.iterate(0, n -> n + 1)                 .limit(1000)                 .collect(Collectors.toList());         INTEGERS.addAll(list);     }
      @Benchmark     public void splitTest(){         List<List<Integer>> listList = split(INTEGERS, 3);     }     @Benchmark     public void split2Test(){         List<List<Integer>> listList = split2(INTEGERS, 3);     }
      public static <T> List<List<T>> split(List<T> lists, int subCount) {                  int splitTimes = (lists.size() + subCount - 1) / subCount;         return Stream                                  .iterate(0, n -> n + subCount)                                  .limit(splitTimes)                                  .map(item -> lists.stream()                                                  .skip(item)                                                  .limit(subCount)                                                  .collect(Collectors.toList()))                                  .collect(Collectors.toList());     }
      public static <T> List<List<T>> split2(List<T> list, int len) {         if (CollectionUtils.isEmpty(list) || len < 1) {             return null;         }
          List<List<T>> result = new ArrayList<>();
          int size = list.size();         int count = (size + len - 1) / len;
          for (int i = 0; i < count; i++) {             List<T> subList = list.subList(i * len, (Math.min((i + 1) * len, size)));             result.add(subList);         }         return result;     }
   | 
四、后话
其中不错的一点我觉得是
1
   | int splitTimes = (lists.size() + subCount - 1) / subCount;
   | 
这样巧妙的计算,避免了先取模,后判断是否有余数的繁杂。
这个不是我想到的,也不知道怎么通过数学证明,但是这样就是对的 ==
ps:是谁说数学没用的 ????