github.com/chenjiandongx/go-queue@v0.0.0-20191023082232-e2a36f382f84/README.md (about)

     1  # 📂 collctions
     2  
     3  > Golang 实现的 collections 模块,灵感来自 [Python queue](https://docs.python.org/3/library/queue.html) 和 [Python collections](https://docs.python.org/3/library/collections.html)
     4  
     5  [![Build Status](https://travis-ci.org/chenjiandongx/collections.svg?branch=master)](https://travis-ci.org/chenjiandongx/collections) [![Build status](https://ci.appveyor.com/api/projects/status/b0qa418u4j502086?svg=true)](https://ci.appveyor.com/project/chenjiandongx/collections) [![Go Report Card](https://goreportcard.com/badge/github.com/chenjiandongx/collections)](https://goreportcard.com/report/github.com/chenjiandongx/collections) [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT) [![GoDoc](https://godoc.org/github.com/chenjiandongx/collections?status.svg)](https://godoc.org/github.com/chenjiandongx/collections)
     6  
     7  ## 📚 目录
     8  
     9  * [Queue - 先进先出队列](#Queue)
    10  * [LifoQueue - 后进先出队列](#LifoQueue)
    11  * [PriorityQueue - 优先队列](#PriorityQueue)
    12  * [Deque - 双端队列](#Deque)
    13  * [OrderedMap - 有序 Map](#OrderedMap)
    14  * [Counter - 计数器](#Counter)
    15  * [AVLTree - AVL 树](#AVLTree)
    16  * [Sort - 排序](#Sort)
    17  
    18  ### 🔰 安装&引用
    19  
    20  ```bash
    21  $ go get github.com/chenjiandongx/collections
    22  
    23  import "github.com/chenjiandongx/collections"
    24  ```
    25  
    26  ### 📦 Collections
    27  
    28  ### Queue
    29  > 先进先出队列(线程安全)
    30  
    31  📝 方法集
    32  ```shell
    33  Get()(interface{}, bool)    // 出队
    34  Put(v interface{})          // 入队
    35  Qsize() int                 // 返回队列长度
    36  IsEmpty() bool              // 判断队列是否为空
    37  ```
    38  
    39  ✏️ 示例
    40  ```go
    41  var nums = 1000
    42  
    43  q := collections.NewQueue()
    44  var item interface{}
    45  var ok bool
    46  for i := 0; i < nums; i++ {
    47      q.Put(i)
    48  }
    49  for i := 0; i < nums; i++ {
    50      if item, ok = q.Get(); ok {
    51          fmt.Println(item.(int))
    52      }
    53  }
    54  
    55  fmt.Println(q.IsEmpty())
    56  fmt.Println(q.Qsize())
    57  ```
    58  
    59  ### LifoQueue
    60  > 后进先出队列(线程安全)
    61  
    62  📝 方法集
    63  ```shell
    64  Get()(interface{}, bool)    // 出队
    65  Put(v interface{})          // 入队
    66  Qsize() int                 // 返回队列长度
    67  IsEmpty() bool              // 判断队列是否为空
    68  ```
    69  
    70  ✏️ 示例
    71  ```go
    72  var nums = 1000
    73  
    74  q := collections.NewLifoQueue()
    75  var item interface{}
    76  var ok bool
    77  for i := 0; i < nums; i++ {
    78      q.Put(i)
    79  }
    80  for i := nums-1; i >=0; i-- {
    81      if item, ok = q.Get(); ok {
    82          fmt.Println(item.(int))
    83      }
    84  }
    85  
    86  fmt.Println(q.IsEmpty())
    87  fmt.Println(q.Qsize())
    88  ```
    89  
    90  ### PriorityQueue
    91  > 优先队列(线程安全)
    92  
    93  📝 方法集
    94  ```shell
    95  Get()(interface{}, bool)    // 出队
    96  Put(v *PqNode)              // 入队
    97  Qsize() int                 // 返回队列长度
    98  IsEmpty() bool              // 判断队列是否为空
    99  
   100  // 优先队列节点
   101  type PqNode struct {
   102      Value           string
   103      Priority, index int
   104  }
   105  ```
   106  
   107  ✏️ 示例
   108  ```go
   109  var nums = 1000
   110  
   111  q := collections.NewPriorityQueue()
   112  
   113  for i := 0; i < nums; i++ {
   114      r := rand.Int()
   115      q.Put(&collections.PqNode{Value: string(r), Priority: rand.Int()})
   116  }
   117  
   118  for i := 0; i < nums/2; i++ {
   119      item1, _ := q.Get()
   120      item2, _ := q.Get()
   121      fmt.Println(item1.(*collections.PqNode).Priority > item2.(*collections.PqNode).Priority)
   122  }
   123  
   124  fmt.Println(q.IsEmpty())
   125  fmt.Println(q.Qsize())
   126  ```
   127  
   128  ### Deque
   129  > 双端队列(线程安全)
   130  
   131  📝 方法集
   132  ```shell
   133  GetLeft()(interface{}, bool)        // 左边出队
   134  GetRight()(interface{}, bool)       // 右边出队
   135  PutLeft(v interface{})              // 左边入队
   136  PutRight(v interface{})             // 右边入队
   137  Qsize() int                         // 返回队列长度
   138  IsEmpty() bool                      // 判断队列是否为空
   139  ```
   140  
   141  ✏️ 示例
   142  ```go
   143  var nums = 1000
   144  q := collections.NewDeque()
   145  
   146  var item interface{}
   147  var ok bool
   148  
   149  for i := 0; i < nums; i++ {
   150      q.PutLeft(i)
   151  }
   152  fmt.Println(q.Qsize())
   153  
   154  for i := nums - 1; i >= 0; i-- {
   155      q.PutRight(i)
   156  }
   157  fmt.Println(q.Qsize())
   158  
   159  for i := 0; i < nums; i++ {
   160      item, ok = q.GetRight()
   161      fmt.Println(item, ok)
   162  }
   163  for i := nums - 1; i >= 0; i-- {
   164      item, ok = q.GetLeft()
   165      fmt.Println(item, ok)
   166  }
   167  
   168  item, ok = q.GetLeft()
   169  fmt.Println(item, ok)
   170  
   171  item, ok = q.GetRight()
   172  fmt.Println(item, ok)
   173  ```
   174  
   175  ### OrderedMap
   176  > 有序 Map,接口设计参考 [cevaris/ordered_map](https://github.com/cevaris/ordered_map)
   177  
   178  📝 方法集
   179  ```shell
   180  Set(key, value interface{})                 // 新增键值对
   181  Get(key interface{}) (interface{}, bool)    // 取值
   182  Delete(key interface{}) bool                // 删除键
   183  Iter() (interface{}, interface{}, bool)     // 遍历
   184  Len() int                                   // 键值对数量
   185  // 指针回退到 Head,遍历时 current 指针会向后移动 BackToHead 使其移动到头指针,以便下一次从头遍历
   186  BackToHead()                               
   187  ```
   188  
   189  ✏️ 示例
   190  ```go
   191  maxNum := 100
   192  om := collections.NewOrderedMap()
   193  for i := 0; i < maxNum; i++ {
   194      om.Set(i, i+1)
   195  }
   196  
   197  fmt.Println(om.Len())
   198  om.Delete(0)
   199  fmt.Println(om.Len())
   200  
   201  for k, v, ok := om.Iter(); ok; k, v, ok = om.Iter() {
   202      fmt.Println(k, v)
   203  }
   204  
   205  om.BackToHead()
   206  for k, v, ok := om.Iter(); ok; k, v, ok = om.Iter() {
   207      fmt.Println(k, v)
   208  }
   209  ```
   210  
   211  📣 讨论
   212  
   213  有序 Map 在 Golang 中应该是十分常见的需求,Map 最大的优势就是其查找性能,**理论上** Map 查找的时间复杂度为常数级。但实际情况我们可以通过 benchmark 来验证。在 [Go Maps Don’t Appear to be O(1)](https://medium.com/@ConnorPeet/go-maps-are-not-o-1-91c1e61110bf) 这篇文章中,作者测试了 Golang Map 查找的实际性能,不过作者是基于 Go1.4 的,版本有点旧了。下面是我修改了作者的测试案例后在 Go1.10 下跑出来的结果。
   214  
   215  ![](https://user-images.githubusercontent.com/19553554/51075377-83f8cd80-16c5-11e9-9973-4904a4661aeb.png)
   216  
   217  上图是使用 [go-echarts](https://github.com/go-echarts/go-echarts) 绘制的。测试通过与二分查找对比,二分查找的时间复杂度为 **O(log2n)**。很明显,在 10e5 数量级下两者的性能差别还不是特别大,主要差距是在 10e6 后体现的。结论:Map 的性能优于 **O(log2n)**,但不是常数级。
   218  
   219  **collections.OrderdMap 🆚 cevaris/ordered_map**
   220  
   221  本来我一直使用的是 [cevaris/ordered_map](https://github.com/cevaris/ordered_map),后来自己重新实现了一个。实现完就与其进行了性能测试对比,它是基于两个 Map 实现的,而我是使用的 Map+LinkedList,LinkedList 在删除和插入操作上的时间复杂度都是 **O(1)**,用其来存储 Map key 的顺序是一个很好的选择。
   222  
   223  同样的测试代码,BenchMark 结果如下
   224  ```shell
   225  goos: windows
   226  goarch: amd64
   227  pkg: github.com/chenjiandongx/collections
   228  BenchmarkCollectionsSet-8        2000000               689 ns/op             187 B/op          3 allocs/op
   229  BenchmarkCevarisSet-8            1000000              1212 ns/op             334 B/op          3 allocs/op
   230  BenchmarkCollectionsGet-8        2000000               823 ns/op             187 B/op          3 allocs/op
   231  BenchmarkCevarisGet-8            1000000              1281 ns/op             334 B/op          3 allocs/op
   232  BenchmarkCollectionsIter-8       2000000               670 ns/op             187 B/op          3 allocs/op
   233  BenchmarkCevarisIter-8           1000000              1341 ns/op             366 B/op          4 allocs/op
   234  ```
   235  **collections.OrderedMap Win 🖖 性能+内存占用全部占优 🚀**
   236  
   237  ### Counter
   238  > 计数器
   239  
   240  📝 方法集
   241  ```shell
   242  // key-value item
   243  type Item struct {
   244      k interface{}
   245      v int
   246  }
   247  
   248  Add(keys ...interface{})            // 新增 item
   249  Get(key interface{}) int            // 获取 key 计数
   250  GetAll() []Item                     // 获取全部 key 计数
   251  Top(n int) []Item                   // 获取前 key 计数
   252  Delete(key interface{}) bool        // 删除 key,成功返回 true,key 不存在返回 false
   253  Len() int                           // key 数量
   254  ```
   255  
   256  ✏️ 示例
   257  ```go
   258  c := collections.NewCounter()
   259  c.Add("a", "b", "c", "d", "a", "c")
   260  fmt.Println(c.Get("A"))
   261  fmt.Println(c.Get("a"))
   262  fmt.Println(c.Get("b"))
   263  fmt.Println(c.Top(2))
   264  fmt.Println(c.Len())
   265  fmt.Println(c.All())
   266  c.Delete("a")
   267  ```
   268  
   269  ### AVLTree
   270  > AVL 二叉自平衡查找树
   271  
   272  📝 方法集
   273  ```shell
   274  NewAVLTree() *AVLTree       // 生成 AVL 树
   275  Insert(v int)               // 插入节点
   276  Search(v int) bool          // 搜索节点
   277  Delete(v int) bool          // 删除节点
   278  GetMaxValue() int           // 获取所有节点中的最大值
   279  GetMinValue() int           // 获取所有节点中的最小值
   280  AllValues() []int           // 返回排序后所有值
   281  ```
   282  
   283  ✏️ 示例
   284  ```go
   285  var maxNum = 100
   286  
   287  tree := NewAVLTree()
   288  for i := 0; i < maxNum; i++ {
   289      tree.Insert(i)
   290      tree.Insert(maxNum + i)
   291  }
   292  fmt.Println(len(tree.AllValues()))
   293  fmt.Println(tree.GetMaxValue())
   294  fmt.Println(tree.GetMinValue())
   295  fmt.Println(tree.Search(50))
   296  fmt.Println(tree.Search(100))
   297  fmt.Println(tree.Search(-10))
   298  fmt.Println(tree.Delete(-10))
   299  fmt.Println(tree.Delete(10))
   300  ```
   301  
   302  📣 讨论
   303  
   304  AVL 树是自平衡树的一种,其通过左旋和右旋来调整自身的平衡性,使其左右子树的高度差最大不超过 1。AVL 在插入、查找、删除的平时时间复杂度都是 O(logn),在基本的 BST(二叉查找树)中,理想情况的效率也是为 O(logn),但由于操作的性能其实是依赖于树的高度,BST 最坏的情况会导致树退化成链表,此时时间复杂度就变为 O(n),为了解决这个问题,自平衡二叉树应运而生。
   305  
   306  AVL 的主要精髓在于`旋转`,旋转分为 4 种情况,左旋,左旋+右旋,右旋,右旋+左旋。调整树结构后需要重新计算树高。
   307  
   308  **左子树左节点失衡**
   309  > 左左情况 直接右旋
   310  ```shell
   311      x                
   312    x        => 右旋         x
   313  x                       x    x
   314  ```
   315  
   316  **左子树右节点失衡**
   317  > 左右情况 先左旋后右旋
   318  ```shell
   319    x                        x     
   320  x         => 左旋         x       => 右旋        x
   321    x                     x                     x    x
   322  ```
   323  
   324  **右子树右节点失衡**
   325  > 右右情况 直接左旋
   326  ```shell
   327  x                
   328    x       => 左旋          x
   329      x                   x    x
   330  ```
   331  
   332  **右子树左节点失衡**
   333  > 右左情况 先右旋后左旋
   334  ```shell
   335  x                      x     
   336    x       => 右旋        x       => 左旋        x
   337  x                          x                 x    x
   338  ```
   339  
   340  AVL 主要的性能消耗主要在插入,因为其需要通过旋转来维护树的平衡,但如果使用场景是经常需要排序和查找数据的话,AVL 还是可以展现其良好的性能的。
   341  
   342  **benchmark**
   343  ```
   344  BenchmarkAVLInsert10e1-6        2000000000               0.00 ns/op
   345  BenchmarkAVLInsert10e2-6        2000000000               0.00 ns/op
   346  BenchmarkAVLInsert10e3-6        2000000000               0.00 ns/op
   347  BenchmarkAVLInsert10e4-6        2000000000               0.02 ns/op
   348  BenchmarkAVLInsert10e5-6        1000000000               0.82 ns/op
   349  BenchmarkAVLSearch-6            2000000000               0.00 ns/op
   350  BenchmarkAVLDelete-6            2000000000               0.00 ns/op
   351  ```
   352  
   353  ### Sort
   354  
   355  📝 方法集
   356  ```shell
   357  BubbleSort()        // 冒泡排序
   358  InsertionSort()     // 插入排序
   359  QuickSort()         // 快速排序
   360  ShellSort()         // 希尔排序
   361  HeapSort()          // 堆排序
   362  MergeSort()         // 归并排序
   363  ```
   364  
   365  ✏️ 示例
   366  ```go
   367  var maxCnt = 10e4
   368  
   369  func yieldRandomArray() []int {
   370      res := make([]int, maxCnt)
   371      for i := 0; i < maxCnt; i++ {
   372          res[i] = rand.Int()
   373      }
   374      return res
   375  }
   376  
   377  BubbleSort(yieldRandomArray())
   378  InsertionSort(yieldRandomArray())
   379  QuickSort(yieldRandomArray())
   380  ShellSort(yieldRandomArray())
   381  HeapSort(yieldRandomArray())
   382  MergeSort(yieldRandomArray())
   383  ```
   384  
   385  📣 讨论
   386  
   387  **排序算法时间复杂度比较**
   388  
   389  | 排序算法 |  是否稳定  |  平均    |   最好  |    最差   |   动画演示  |
   390  | -------- | --------- |----------| --------| -------- | ----------- |
   391  | BubbleSort | 是 | O(n^2) |  O(n) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/3/37/Bubble_sort_animation.gif) |
   392  | InsertionSort | 是 | O(n^2) |  O(n) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/2/25/Insertion_sort_animation.gif) |
   393  | QuickSort | 否 | O(nlogn) | O(nlogn) |  O(n^2) | ![](https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif) |
   394  | ShellSort | 否 |O(nlogn) |  O(n) | O(n^2)  | ![](https://upload.wikimedia.org/wikipedia/commons/2/25/Insertion_sort_animation.gif) |
   395  | HeapSort | 否 | O(nlogn) |  O(nlogn) | O(nlogn) | ![](https://upload.wikimedia.org/wikipedia/commons/1/1b/Sorting_heapsort_anim.gif) |
   396  | MergeSort | 是 | O(nlogn) |  O(nlogn) | O(nlogn) | ![](https://upload.wikimedia.org/wikipedia/commons/c/c5/Merge_sort_animation2.gif) |
   397  
   398  通过 benchmark 来测试平均排序性能
   399  
   400  **数据随机分布**
   401  ```go
   402  var maxCnt int = 10e4
   403  
   404  func yieldRandomArray(cnt int) []int {
   405      res := make([]int, cnt)
   406      for i := 0; i < cnt; i++ {
   407          res[i] = rand.Int()
   408      }
   409      return res
   410  }
   411  ```
   412  
   413  运行结果
   414  ```shell
   415  BenchmarkBubbleSort-8                  1        17361549400 ns/op
   416  BenchmarkInsertionSort-8               1        1934826900 ns/op
   417  BenchmarkQuickSort-8                 100          10651807 ns/op
   418  BenchmarkShellSort-8                 100          16476199 ns/op
   419  BenchmarkHeapSort-8                  100          14231607 ns/op
   420  BenchmarkMergeSort-8                 100          14840583 ns/op
   421  ```
   422  
   423  冒泡和直接插入排序在随机数据集的排序性能最差,为 O(n^2),剩余 4 种排序快排效率最佳,其他 3 者性能很接近。
   424  
   425  **换两种极端的数据分布方式**
   426  
   427  **数据升序分布**
   428  ```go
   429  func yieldArrayAsce(cnt int) []int {
   430      res := make([]int, cnt)
   431      for i := 0; i < cnt; i++ {
   432          res[i] = i
   433      }
   434      return res
   435  }
   436  ```
   437  
   438  运行结果
   439  ```shell
   440  BenchmarkBubbleSort-8               5000            266690 ns/op
   441  BenchmarkInsertionSort-8           10000            213429 ns/op
   442  BenchmarkQuickSort-8                   1        3291222900 ns/op
   443  BenchmarkShellSort-8                1000           1716406 ns/op
   444  BenchmarkHeapSort-8                  200           6806788 ns/op
   445  BenchmarkMergeSort-8                 300           4677485 ns/op
   446  ```
   447  
   448  在数据基本升序的情况下,冒泡和直接插入排序能够取得良好的性能。而快排就给跪了,就是最差的 O(n^2) 了。
   449  
   450  **数据降序分布**
   451  ```go
   452  func yieldArrayDesc(cnt int) []int {
   453      res := make([]int, cnt)
   454      for i := 0; i < cnt; i++ {
   455          res[i] = cnt-i
   456      }
   457      return res
   458  }
   459  ```
   460  
   461  运行结果
   462  ```shell
   463  BenchmarkBubbleSort-8                  1        6710048800 ns/op
   464  BenchmarkInsertionSort-8               1        3881599100 ns/op
   465  BenchmarkQuickSort-8                   1        3373971200 ns/op
   466  BenchmarkShellSort-8                 500           2876371 ns/op
   467  BenchmarkHeapSort-8                  200           7081150 ns/op
   468  BenchmarkMergeSort-8                 300           4448222 ns/op
   469  ```
   470  
   471  在数据基本降序的情况下,冒泡和直接插入排序一如既往的差,快排又给跪了,又是 O(n^2)...
   472  
   473  那自己实现的排序和 Golang 官方提供的 sort.Sort 排序方法对比,效率如何呢
   474  
   475  
   476  定义一个 struct,实现 sort.Interface
   477  ```go
   478  import "sort"
   479  
   480  type StdItems struct {
   481      data []int
   482  }
   483  
   484  func (o StdItems) Less(i, j int) bool {
   485      return o.data[i] < o.data[j]
   486  }
   487  
   488  func (o StdItems) Swap(i, j int) {
   489      o.data[i], o.data[j] = o.data[j], o.data[i]
   490  }
   491  
   492  func (o StdItems) Len() int {
   493      return len(o.data)
   494  }
   495  ```
   496  
   497  只取 n(logn) 复杂度的排序算法与标准 sort 进行对比
   498  
   499  **数据随机分布**
   500  ```shell
   501  BenchmarkStdSort-8                            50          22978524 ns/op
   502  BenchmarkQuickSort-8                         100          11648689 ns/op
   503  BenchmarkShellSort-8                         100          17353544 ns/op
   504  BenchmarkHeapSort-8                          100          14501199 ns/op
   505  BenchmarkMergeSort-8                         100          13793086 ns/op
   506  ```
   507  
   508  是不是眼前一亮 😂,自己写的快排居然这么厉害,比标准的 sort 快了不止两倍??? 这里出现这种情况的主要原因是 sort 实现了 sort.Interface,该接口需要有三个方法 Less()/Len()/Swap(),而接口的类型转换是有成本的。**通用意味着兼容,兼容意味着妥协,这是专和精权衡后的结果**。当然,标准的 sort 大部分情况的性能都是可接受的。但当你需要追求极致性能的话,自己针对特定需求实现排序算法肯定会是更好的选择。
   509  
   510  **数据升序分布**
   511  ```shell
   512  BenchmarkStdSort-8                           200           7285511 ns/op
   513  BenchmarkQuickSort-8                           1        3351046900 ns/op
   514  BenchmarkShellSort-8                        1000           1679506 ns/op
   515  BenchmarkHeapSort-8                          200           6632256 ns/op
   516  BenchmarkMergeSort-8                         300           4308582 ns/op
   517  ```
   518  
   519  是不是又是眼前一亮 🤣,我去 为什么这次标准的排序比快排快了这么多,官方的排序不也是快排吗?(这个测试结果看起来好像也没人会比快排慢是吧 😅)
   520  
   521  **数据降序分布**
   522  ```shell
   523  BenchmarkStdSort-8                           200           7405331 ns/op
   524  BenchmarkQuickSort-8                           1        3390954400 ns/op
   525  BenchmarkShellSort-8                         500           2900240 ns/op
   526  BenchmarkHeapSort-8                          200           7091124 ns/op
   527  BenchmarkMergeSort-8                         300           4295169 ns/op
   528  ```
   529  
   530  emmmmmmm,同上 😓
   531  
   532  关于官方排序的具体实现,可以参考 [src/sort/sort.go](https://golang.org/src/sort/sort.go),实际上是直接插入排序,快速排序,堆排序和归并排序的组合排序。[这篇文章](https://github.com/polaris1119/The-Golang-Standard-Library-by-Example/blob/master/chapter03/03.1.md) 对这部分有介绍
   533  
   534  最后,按官方的排序针对自己想要的数据类型排序,但不使用接口那套,对比上面排序中最快的算法以及接口实现的 sort
   535  
   536  **数据随机分布**
   537  ```shell
   538  BenchmarkStdSort-8                           100          22649399 ns/op
   539  BenchmarkQuickSort-8                         100          10870924 ns/op
   540  BenchmarkStdSortWithoutInterface-8           100          10511605 ns/op
   541  ```
   542  
   543  **数据升序分布**
   544  ```shell
   545  BenchmarkStdSort-8                           200           7006117 ns/op
   546  BenchmarkShellSort-8                        1000           1667537 ns/op
   547  BenchmarkStdSortWithoutInterface-8          1000           1619643 ns/op
   548  ```
   549  
   550  **数据降序分布**
   551  ```shell
   552  BenchmarkStdSort-8                           200           7614625 ns/op
   553  BenchmarkShellSort-8                         500           3051834 ns/op
   554  BenchmarkStdSortWithoutInterface-8          1000           1689479 ns/op
   555  ```
   556  
   557  🖖 [StdSortWithoutInterface](https://github.com/chenjiandongx/collections/blob/master/std_sort.go) 完胜!!!
   558  
   559  我们还可以进一步思考如何获得更高的排序性能,使用 goroutine 将一个数据切分成两半,分别使用 `StdSortWithoutInterface` 排序,将排序后的结果进行一次归并排序,就可以得到最终的有序数组,这次我们测试的数组长度为 **10e5**
   560  
   561  为了验证真正的`并行计算` 我们将分别测试 cpu 数量为 1, 2, 8 的情况
   562  ```shell
   563  BenchmarkStdSort                               5         260696480 ns/op
   564  BenchmarkStdSort-2                             5         246746560 ns/op
   565  BenchmarkStdSort-8                             5         248532560 ns/op
   566  BenchmarkStdSortWithoutInterface              10         124666470 ns/op
   567  BenchmarkStdSortWithoutInterface-2            10         120676740 ns/op
   568  BenchmarkStdSortWithoutInterface-8            10         126062650 ns/op
   569  BenchmarkStdSortWithGoroutine                 20         125163280 ns/op
   570  BenchmarkStdSortWithGoroutine-2               20          80835825 ns/op
   571  BenchmarkStdSortWithGoroutine-8               20          81232625 ns/op
   572  ```
   573  
   574  😎 WOW!!! cpu 数量为 1 时大家相差无几,cpu > 1 以后,goroutine 做到了真正的并行,利用多核进行计算,速度提升了 **1.5** 倍,比默认的 Sort 方法提升了 **4** 倍。喏,这就是算法的魅力。
   575  
   576  ### 📃 License
   577  MIT [©chenjiandongx](http://github.com/chenjiandongx)