|
| 1 | +- [stl\_extension 模块](#stl_extension-模块) |
| 2 | + - [LimitWaitGroup](#limitwaitgroup) |
| 3 | + - [OrderedMap](#orderedmap) |
| 4 | + |
| 5 | +# stl_extension 模块 |
| 6 | + |
| 7 | +stl_extension 模块主要是对系统的 stl 的不足做补充。 |
| 8 | + |
| 9 | +## LimitWaitGroup |
| 10 | +对原生 stl 的 WaitGroup 做补充,原生的 WaitGroup 没有办法限制协程的数量,比如如下处理, |
| 11 | +```go |
| 12 | +group := sync.WaitGroup{} |
| 13 | +for i := 0; i < 10000; i++ { |
| 14 | + v := i |
| 15 | + group.Add(1) |
| 16 | + go func() { |
| 17 | + defer group.Done() |
| 18 | + fmt.Print(v) |
| 19 | + }() |
| 20 | +} |
| 21 | +group.Wait() |
| 22 | +``` |
| 23 | +会在一瞬间创建大量的协程。而用 LimitWaitGroup,可以实现限制并发的协程数量。 |
| 24 | + |
| 25 | +```go |
| 26 | +// 10 协程并发 |
| 27 | +group := stlextension.NewLimitWaitGroup(10) |
| 28 | +for i := 0; i < 10000; i++ { |
| 29 | + v := i |
| 30 | + // 如果协程并发满了,会阻塞等待 |
| 31 | + group.Add(1) |
| 32 | + go func() { |
| 33 | + defer group.Done() |
| 34 | + fmt.Print(v) |
| 35 | + }() |
| 36 | +} |
| 37 | +group.Wait() |
| 38 | +``` |
| 39 | + |
| 40 | +## OrderedMap |
| 41 | +golang stl 原生的 map 是基于 hash 的无需 map,OrderedMap 是对 hash map 的补充。支持按照 key 顺序遍历。 |
| 42 | +OrderedMap 使用 avl 树实现,是线程安全的。 |
| 43 | +和 c++ map 对比测试,1000 万的随机的增删查操作: |
| 44 | +OrderedMap: 21806 ms, c++ map: 11592ms,效率比 c++ map 慢两倍。 |
| 45 | +next 遍历整个 map, OrderedMap: 676ms, c++ map: 171ms; |
| 46 | +prev 遍历整个 map, OrderedMap: 663ms, c++ map: 198ms; |
| 47 | +遍历的效率大概比 c++ map 的慢三倍。 |
| 48 | + |
| 49 | +用法: |
| 50 | +- 构建 |
| 51 | +```go |
| 52 | +m := stlextension.OrderedMap{} |
| 53 | +``` |
| 54 | + |
| 55 | +- 判断 map 是否为空 |
| 56 | +```go |
| 57 | +m.Empty() |
| 58 | +``` |
| 59 | + |
| 60 | +- 插入: 插入的 key 必须实现 stlextension.Key Less interface,也就是必须要实现比较方法,value 可以是任意 interface{}。如果插入的 key 和其他之前插入的旧的 key 比较的时候失败,插入也会失败。 |
| 61 | + |
| 62 | +```go |
| 63 | +err := m.Insert(stlextension.IntKey(5), "BBB"); |
| 64 | +``` |
| 65 | + |
| 66 | +- 删除:插入的 key 必须实现 stlextension.Key Less interface,也就是必须要实现比较方法。 |
| 67 | +```go |
| 68 | +err := m.Erase(stlextension.IntKey(5)); |
| 69 | +``` |
| 70 | + |
| 71 | +- 计数:计算 map 中的 key 的数量。 |
| 72 | +```go |
| 73 | +num, err := m.Count(stlextension.IntKey(4)) |
| 74 | +``` |
| 75 | + |
| 76 | +- Find: 寻找 key 的 value。 |
| 77 | +```go |
| 78 | +value, exixt, err := m.Find(stlextension.IntKey(5)) |
| 79 | +``` |
| 80 | + |
| 81 | +- Begin: Begin 获取 key 最小的元素的 key 和 value,配合 Next 进行迭代。 |
| 82 | +- Next: 按照 key 的顺序获取当前 key 的下一个 key 和 value。 |
| 83 | +```go |
| 84 | +// test begin and next |
| 85 | +for key, value := m.Begin(); key != nil; key, value, err = m.Next(key) { |
| 86 | + if err != nil { |
| 87 | + log.Fatalf("test next error: %v", err) |
| 88 | + } |
| 89 | + log.Printf("key: %v, value: %v", key, value) |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +- RBegin: RBegin 获取 key 最大的元素的 key 和 value,配合 Prev 进行方向迭代。 |
| 94 | +- Prev: 按照 key 的顺序获取当前 key 的前一个 key 和 value。 |
| 95 | +```go |
| 96 | +// test rbegin and prev |
| 97 | +for key, value := m.RBegin(); key != nil; key, value, err = m.Prev(key) { |
| 98 | + if err != nil { |
| 99 | + log.Fatalf("test prev error: %v", err) |
| 100 | + } |
| 101 | + log.Printf("key: %v, value: %v", key, value) |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +- Clear: 清空 map。 |
| 106 | +```go |
| 107 | +m.Clear() |
| 108 | +``` |
| 109 | + |
| 110 | +- Size: map 元素个数。 |
| 111 | +```go |
| 112 | +s := m.Size() |
| 113 | +``` |
| 114 | + |
| 115 | +- String: map 转换成 string 输出。 |
| 116 | +```go |
| 117 | +log.Print(m.String()) |
| 118 | +``` |
| 119 | + |
| 120 | +example 参考:[TestOrderMap](https://github.com/memory-overflow/go-common-library/blob/main/stl_extension/stl_test.go#L13)。 |
0 commit comments