github.com/songzhibin97/gkit@v1.2.13/README_zh.md (about)

     1  # GKIT
     2  
     3  ```
     4  _____/\\\\\\\\\\\\__/\\\________/\\\__/\\\\\\\\\\\__/\\\\\\\\\\\\\\\_        
     5   ___/\\\//////////__\/\\\_____/\\\//__\/////\\\///__\///////\\\/////__       
     6    __/\\\_____________\/\\\__/\\\//_________\/\\\___________\/\\\_______      
     7     _\/\\\____/\\\\\\\_\/\\\\\\//\\\_________\/\\\___________\/\\\_______     
     8      _\/\\\___\/////\\\_\/\\\//_\//\\\________\/\\\___________\/\\\_______    
     9       _\/\\\_______\/\\\_\/\\\____\//\\\_______\/\\\___________\/\\\_______   
    10        _\/\\\_______\/\\\_\/\\\_____\//\\\______\/\\\___________\/\\\_______  
    11         _\//\\\\\\\\\\\\/__\/\\\______\//\\\__/\\\\\\\\\\\_______\/\\\_______ 
    12          __\////////////____\///________\///__\///////////________\///________                                 
    13  ```
    14  
    15  
    16  # 项目简介
    17  致力于提供微服务以及单体服务的可用性基础组件工具集合,借鉴了一些优秀的开源项目例如:`kratos`、`go-kit`、`mosn`、`sentinel`、`gopkg`... 希望大家多多支持
    18  
    19  # 目录结构
    20  ```shell
    21  ├── cache (构建缓存相关组件)
    22    ├── buffer (提供byte数组复用以及io buffer封装)
    23    ├── mbuffer (buffer 类似实现) 
    24    ├── local_cache (提供本地key-value构建本地缓存的封装实现)
    25    ├── singleflight (提供高并发情况下防止重复任务,一般用于cache miss后填补cache场景)
    26  ├── coding (提供对象序列化/反序列化接口化, 提供json、proto、xml、yaml 实例方法)
    27  ├── concurrent (在并发中使用channel的最佳实践)
    28    ├── fan_in (扇入模式,常用与生产者消费者模型中多个生产者,一个消费者)
    29    ├── fan_out (扇出模式,常用与生产着消费者模型中一个生产者,多个消费者)
    30    ├── or_done (并发场景下任意一个任务完成后立即返回)
    31    ├── orderly (在并发场景下也能保持有序的完成返回)
    32    ├── map_reduce 
    33    ├── stream (提供数据生产流封装,以及处理流的实现)
    34    ├── pipeline (并发变为串行)
    35  ├── container (容器化组件,提供group、pool、queue)
    36    ├── group (提供了容器懒加载模式,类似sync.Pool,在使用时使用key获取对应容器实例,如果不存在则进行生成)
    37    ├── pool (提供了pool的封装抽象,以及使用list对接口的实现)
    38    ├── queue
    39      ├── codel (对列实现可控制延时算法,对积压任务实现制裁)
    40  ├── delayed (延时任务-单机版)
    41  ├── distributed (分布式任务,提供了标准化接口以及redis、mysql、pgsql、mongodb对应的实现)
    42  ├── downgrade (熔断降级相关组件)
    43  ├── egroup (errgroup,控制组件生命周期)
    44  ├── encrypt (加密封装,保护padkey补全)
    45  ├── errors (grpc error处理)
    46  ├── gctuner (go1.19前优化gc利器)
    47  ├── generator (发号器,snowflake)
    48  ├── goroutine (提供goroutine池,控制goroutine数量激增)
    49  ├── log (接口化日志,使用日志组件接入)
    50  ├── metrics (指标接口化)
    51  ├── middleware (中间件接口模型定义)
    52  ├── net (网络相关封装)
    53    ├── tcp
    54  ├── options (选项模式接口化)
    55  ├── overload (服务器自适应保护,提供bbr接口,监控部署服务器状态选择流量放行,保护服务器可用性)
    56    ├── bbr (自适应限流)
    57  ├── page_token (google aip next token 实现)  
    58  ├── parser (文件解析,proto<->go相互解析)
    59    ├── parseGo (解析go生成pb)
    60    ├── parsePb (解析pb生成go)
    61  ├── registry (服务发现接口化、google sre subset实现)
    62  ├── restrictor (限流,提供令牌桶和漏桶接口封装)
    63    ├── client_throttling (客户端节流)
    64    ├── rate 
    65    ├── ratelimite 
    66  ├── structure (常用数据结构)
    67    ├── hashset (哈希表)
    68    ├── lscq (无锁无边界队列,支持arm)
    69    ├── skipmap 
    70    ├── skipset 
    71    ├── zset 
    72  ├── sync
    73      ├── cpu (获取Linux平台下的系统信息,包括cpu主频、cpu使用率等)
    74      ├── fastrand (随机数)
    75      ├── goid (获取goroutine id)
    76      ├── mutex (提供trylock、重入锁和token重入锁)
    77      ├── nanotime (时间戳优化)
    78      ├── once (once 更强大的实现,设置once函数增加返回error,失败后可重试)
    79      ├── queue (无锁队列)
    80      ├── safe (底层string,slice 结构)
    81      ├── stringx (string 增强版)
    82      ├── syncx (sync 增强版)
    83      ├── xxhash3 
    84  ├── ternary (三元表达式)    
    85  ├── timeout (超时控制,全链路保护、提供一些数据库处理时间的封装实现)
    86    ├── ctime (链路超时控制)
    87    ├── c_json (适配数据库json类型)
    88    ├── d_time (适配数据库 只存储时间)
    89    ├── date (适配数据库 只存储日期)
    90    ├── date_struct (适配数据库 只存储日期)
    91    ├── datetime (适配数据库 存储datetime)
    92    ├── datetime_struct (适配数据库 存储datetime)
    93    ├── stamp (适配数据库 存储时间戳)
    94    ├── human (提供可视化时间间距)
    95  ├── tools 
    96    ├── bind (绑定工具,常用与gin框架中自定义绑定数据,例如同时绑定query和json)
    97    ├── deepcopy (深拷贝)
    98    ├── float (浮点数截断工具)
    99    ├── match (基础匹配器,根据通配符匹配)
   100    ├── pointer (指针工具)
   101    ├── pretty (格式化json)
   102    ├── reflect2value (基础字段映射)
   103    ├── rand_string (随机字符串)
   104    ├── vto (具有相同类型的函数赋值,解放双手,通常用于vo->do对象转换)
   105      ├── vtoPlus (新增plus 支持字段,tag以及默认值绑定)
   106  ├── trace (链路追踪)
   107  ├── watching (监控cpu、mum、gc、goroutine等指标信息,在波动的情况下自动dump pprof指标)
   108  └── window (滑动窗口,支持多数据类型指标窗口收集)
   109  
   110  ```
   111  
   112  # 下载使用
   113  ```shell
   114  # go get github.com/songzhibin97/gkit@master
   115  go get github.com/songzhibin97/gkit
   116  ```
   117  
   118  # 组件使用介绍
   119  ## cache
   120  
   121  缓存相关组件
   122  > buffer&mbuffer 提供的功能类似,buffer多了一些封装,以及实现了io方面的一些接口,而mbuffer仅仅是一个memory的缓存;在生命周期较短且频繁的情况下更适用;
   123  > local_cache 提供了本地的数据缓存,也有一些失效机制,可以设置过期时间,以及定时清理过期数据,但是他现在比较旧了,如果需要的话有泛型版本 https://github.com/songzhibin97/go-baseutils/blob/main/app/bcache
   124  > singleflight 封装了 golang.org/x/sync/singleflight,防止变更带来的影响.
   125  
   126  ### buffer pool
   127  ```go
   128  package main
   129  
   130  import (
   131  	"fmt"
   132  	"github.com/songzhibin97/gkit/cache/buffer"
   133  )
   134  
   135  func main() {
   136  	// Byte复用
   137  
   138  	// size 2^6 - 2^18
   139  	// 返回向上取整的 2的整数倍 cap, len == size
   140  	// 其他特殊的或者在运行期间扩容的 将会被清空
   141  	slice := buffer.GetBytes(1024)
   142  	fmt.Println(len(*slice), cap(*slice)) // 1024 1024
   143  
   144  	// 回收
   145  	// 注意: 回收以后不可在引用
   146  	buffer.PutBytes(slice)
   147  
   148  	// IOByte 复用
   149  
   150  	// io buffer.IoBuffer interface
   151  	io := buffer.GetIoPool(1024)
   152  
   153  	// 如果一个对象已经被回收了,再次引用被回收的对象会触发错误
   154  	err := buffer.PutIoPool(io)
   155  	if err != nil {
   156  		// 处理错误 	    
   157  	}
   158  }
   159  ```
   160  
   161  ### local_cache
   162  ```go
   163  package local_cache
   164  
   165  import (
   166  	"github.com/songzhibin97/gkit/cache/buffer"
   167  	"log"
   168  )
   169  
   170  var ch Cache
   171  
   172  func ExampleNewCache() {
   173  	// 默认配置
   174  	//ch = NewCache()
   175  
   176  	// 可供选择的配置选项
   177  
   178  	// 设置间隔时间
   179  	// SetInternal(interval time.Duration)
   180  
   181  	// 设置默认的超时时间
   182  	// SetDefaultExpire(expire time.Duration)
   183  
   184  	// 设置周期的执行函数,默认(不设置)是扫描全局清除过期的k
   185  	// SetFn(fn func())
   186  
   187  	// 设置触发删除后的捕获函数, 数据删除后回调用设置的捕获函数
   188  	// SetCapture(capture func(k string, v interface{}))
   189  
   190  	// 设置初始化存储的成员对象
   191  	// SetMember(m map[string]Iterator)
   192  
   193  	ch = NewCache(SetInternal(1000),
   194  		SetDefaultExpire(10000),
   195  		SetCapture(func(k string, v interface{}) {
   196  			log.Println(k, v)
   197  		}))
   198  }
   199  
   200  func ExampleCacheStorage() {
   201  	// Set 添加cache 无论是否存在都会覆盖
   202  	ch.Set("k1", "v1", DefaultExpire)
   203  
   204  	// SetDefault 无论是否存在都会覆盖
   205  	// 偏函数模式,默认传入超时时间为创建cache的默认时间
   206  	ch.SetDefault("k1", 1)
   207  
   208  	// SetNoExpire
   209  	// 偏函数模式,默认传入超时时间为永不过期
   210  	ch.SetNoExpire("k1", 1.1)
   211  
   212  	// Add 添加cache 如果存在的话会抛出异常
   213  	err := ch.Add("k1", nil, DefaultExpire)
   214  	CacheErrExist(err) // true
   215  
   216  	// Replace 如果有就设置没有就抛出错误
   217  	err = ch.Replace("k2", make(chan struct{}), DefaultExpire)
   218  	CacheErrNoExist(err) // true
   219  }
   220  
   221  func ExampleGet() {
   222  	// Get 根据key获取 cache 保证有效期内的kv被取出
   223  	v, ok := ch.Get("k1")
   224  	if !ok {
   225  		// v == nil
   226  	}
   227  	_ = v
   228  
   229  	// GetWithExpire 根据key获取 cache 并带出超时时间
   230  	v, t, ok := ch.GetWithExpire("k1")
   231  	if !ok {
   232  		// v == nil
   233  	}
   234  	// 如果超时时间是 NoExpire t.IsZero() == true
   235  	if t.IsZero() {
   236  		// 没有设置超时时间
   237  	}
   238  
   239  	// Iterator 返回 cache 中所有有效的对象
   240  	mp := ch.Iterator()
   241  	for s, iterator := range mp {
   242  		log.Println(s, iterator)
   243  	}
   244  	
   245  	// Count 返回member数量
   246  	log.Println(ch.Count())
   247  }
   248  
   249  func ExampleIncrement() {
   250  	ch.Set("k3", 1, DefaultExpire)
   251  	ch.Set("k4", 1.1, DefaultExpire)
   252  	// Increment 为k对应的value增加n n必须为数字类型
   253  	err := ch.Increment("k3", 1)
   254  	if CacheErrExpire(err) || CacheErrExist(CacheTypeErr) {
   255  		// 未设置成功
   256  	}
   257  	_ = ch.IncrementFloat("k4", 1.1)
   258  
   259  	// 如果你知道设置的k的具体类型 还可以使用类型确定的 increment函数
   260  	// ch.IncrementInt(k string, v int)
   261  	// ...
   262  	// ch.IncrementFloat32(k string, v flot32)
   263  	// ...
   264  
   265  	// Decrement 同理
   266  }
   267  
   268  func ExampleDelete() {
   269  	// Delete 如果设置了 capture 会触发不或函数
   270  	ch.Delete("k1")
   271  
   272  	// DeleteExpire 删除所有过期了的key, 默认的 capture 就是执行 DeleteExpire()
   273  	ch.DeleteExpire()
   274  }
   275  
   276  func ExampleChangeCapture() {
   277  	// 提供了在运行中改变捕获函数的方法
   278  	// ChangeCapture
   279  	ch.ChangeCapture(func(k string, v interface{}) {
   280  		log.Println(k, v)
   281  	})
   282  }
   283  
   284  func ExampleSaveLoad() {
   285  	// 写入文件采用go独有的gob协议
   286  
   287  	io := buffer.NewIoBuffer(1000)
   288  
   289  	// Save 传入一个 w io.Writer 参数 将 cache中的 member 成员写入w中
   290  	_ = ch.Save(io)
   291  
   292  	// SaveFile 传入path 写到文件中
   293  	_ = ch.SaveFile("path")
   294  
   295  	// Load 传入一个 r io.Reader对象 从 r中读取写回到 member中
   296  	_ = ch.Load(io)
   297  
   298  	// LoadFile 传入path 读取文件内容
   299  	_ = ch.LoadFile("path")
   300  }
   301  
   302  func ExampleFlush()  {
   303  	// Flush 释放member成员
   304  	ch.Flush()
   305  }
   306  
   307  func ExampleShutdown()  {
   308  	// Shutdown 释放对象
   309  	ch.Shutdown()
   310  }
   311  ```
   312  
   313  ### singleflight
   314  
   315  归并回源
   316  ```go
   317  package main
   318  
   319  import (
   320  	"github.com/songzhibin97/gkit/cache/singleflight"
   321  )
   322  
   323  // getResources: 一般用于去数据库去获取数据
   324  func getResources() (interface{}, error) {
   325  	return "test", nil
   326  }
   327  
   328  // cache: 填充到 缓存中的数据
   329  func cache(v interface{}) {
   330  	return
   331  }
   332  
   333  func main() {
   334  	f := singleflight.NewSingleFlight()
   335  
   336  	// 同步:
   337  	v, err, _ := f.Do("test1", func() (interface{}, error) {
   338  		// 获取资源
   339  		return getResources()
   340  	})
   341  	if err != nil {
   342  		// 处理错误
   343  	}
   344  	// 存储到buffer
   345  	// v就是获取到的资源
   346  	cache(v)
   347  
   348  	// 异步
   349  	ch := f.DoChan("test2", func() (interface{}, error) {
   350  		// 获取资源
   351  		return getResources()
   352  	})
   353  
   354  	// 等待获取资源完成后,会将结果通过channel返回
   355  	result := <-ch
   356  	if result.Err != nil {
   357  		// 处理错误
   358  	}
   359  	
   360  	// 存储到buffer
   361  	// result.Val就是获取到的资源
   362  	cache(result.Val)
   363  	
   364  	// 尽力取消
   365  	f.Forget("test2")
   366  }
   367  ```
   368  
   369  
   370  ## coding
   371  > 对象序列化反序列化接口以及实例封装,只需要导入匿名,例如json `_ "github.com/songzhibin97/gkit/coding/json"` 也可以实现对应接口后,进行注册,好处是可以控制全局序列化对象以及使用库的统一
   372  
   373  ```go
   374  package main
   375  
   376  import (
   377  	"fmt"
   378  	"github.com/songzhibin97/gkit/coding"
   379  	_ "github.com/songzhibin97/gkit/coding/json" // 一定要提前导入!!!
   380  )
   381  
   382  func main() {
   383  	t := struct {
   384  		Gkit  string
   385  		Lever int
   386  	}{"Gkit", 200}
   387  	fmt.Println(coding.GetCode("json").Name())
   388  	data, err := coding.GetCode("json").Marshal(t)
   389  	if err != nil {
   390  		fmt.Println(err)
   391  		return
   392  	}
   393  	fmt.Println(string(data)) // {"Gkit":"Gkit","Lever":200}
   394  	v := struct {
   395  		Gkit  string
   396  		Lever int
   397  	}{}
   398  	coding.GetCode("json").Unmarshal(data,&v)
   399  	fmt.Println(v) // {Gkit 200}
   400  }
   401  ```
   402  
   403  ## concurrent
   404  
   405  > 并发中channel最佳实践,包含 fan_in,fan_out,map_reduce,or_done,orderly,pipeline,stream,泛型版本可以参考 https://github.com/songzhibin97/go-baseutils/tree/main/app/bconcurrent
   406  
   407  
   408  ## container
   409  
   410  > group 适用于生命周期较长对象的懒加载,类似于 sync.Pool,但是可以自定义创建函数,以及更换初始化函数
   411  > pool 池化对象,通过配置可以设置最大连接数以及等待连接数,同步异步获取连接,以及连接的生命周期管理,可以自定义创建函数,以及更换初始化函数
   412  > codel 实现codel算法,可以用于限流,以及熔断
   413  
   414  ### group
   415  
   416  懒加载容器
   417  ```go
   418  package main
   419  
   420  import (
   421  	"fmt"
   422  	"github.com/songzhibin97/gkit/container/group"
   423  )
   424  
   425  func createResources() interface{} {
   426  	return map[int]int{1: 1, 2: 2}
   427  }
   428  
   429  func createResources2() interface{} {
   430  	return []int{1, 2, 3}
   431  }
   432  
   433  func main() {
   434  	// 类似 sync.Pool 一样
   435  	// 初始化一个group
   436  	g := group.NewGroup(createResources)
   437  
   438  	// 如果key 不存在 调用 NewGroup 传入的 function 创建资源
   439  	// 如果存在则返回创建的资源信息
   440  	v := g.Get("test")
   441  	fmt.Println(v) // map[1:1 2:2]
   442  	v.(map[int]int)[1] = 3
   443  	fmt.Println(v) // map[1:3 2:2]
   444  	v2 := g.Get("test")
   445  	fmt.Println(v2) // map[1:3 2:2]
   446  
   447  	// ReSet 重置初始化函数,同时会对缓存的 key进行清空
   448  	g.ReSet(createResources2)
   449  	v3 := g.Get("test")
   450  	fmt.Println(v3) // []int{1,2,3}
   451  	
   452  	// 清空缓存的 buffer
   453  	g.Clear()
   454  }
   455  ```
   456  
   457  ### pool
   458  
   459  类似资源池
   460  ```go
   461  package main
   462  
   463  import (
   464  	"context"
   465  	"fmt"
   466  	"github.com/songzhibin97/gkit/container/pool"
   467  	"time"
   468  )
   469  
   470  var p pool.Pool
   471  
   472  type mock map[string]string
   473  
   474  func (m *mock) Shutdown() error {
   475  	return nil
   476  }
   477  
   478  // getResources: 获取资源,返回的资源对象需要实现 IShutdown 接口,用于资源回收
   479  func getResources(c context.Context) (pool.IShutdown, error) {
   480  	return &mock{"mockKey": "mockValue"}, nil
   481  }
   482  
   483  func main() {
   484  	// pool.NewList(options ...)
   485  	// 默认配置
   486  	// p = pool.NewList()
   487  
   488  	// 可供选择配置选项
   489  
   490  	// 设置 Pool 连接数, 如果 == 0 则无限制
   491  	// pool.SetActive(100)
   492  
   493  	// 设置最大空闲连接数
   494  	// pool.SetIdle(20)
   495  
   496  	// 设置空闲等待时间
   497  	// pool.SetIdleTimeout(time.Second)
   498  
   499  	// 设置期望等待
   500  	// pool.SetWait(false,time.Second)
   501  
   502  	// 自定义配置
   503  	p = pool.NewList(
   504  		pool.SetActive(100),
   505  		pool.SetIdle(20),
   506  		pool.SetIdleTimeout(time.Second),
   507  		pool.SetWait(false, time.Second))
   508  
   509  	// New需要实例化,否则在 pool.Get() 会无法获取到资源
   510  	p.NewQueue(getResources)
   511  
   512  	v, err := p.Get(context.TODO())
   513  	if err != nil {
   514  		// 处理错误
   515  	}
   516  	fmt.Println(v) // &map[mockKey:mockValue]
   517  
   518  	// Put: 资源回收
   519  	// forceClose: true 内部帮你调用 Shutdown回收, 否则判断是否是可回收,挂载到list上
   520  	err = p.Put(context.TODO(), v, false)
   521  	if err != nil {
   522  		// 处理错误  	    
   523  	}
   524  	
   525  	// Shutdown 回收资源,关闭所有资源
   526  	_ = p.Shutdown()
   527  }
   528  ```
   529  
   530  ### queue
   531  codel实现
   532  ```go
   533  package main
   534  
   535  import (
   536  	"context"
   537  	"fmt"
   538  	"github.com/songzhibin97/gkit/container/queue/codel"
   539  	"github.com/songzhibin97/gkit/overload/bbr"
   540  )
   541  
   542  func main() {
   543  	queue := codel.NewQueue(codel.SetTarget(40), codel.SetInternal(1000))
   544  
   545  	// start 体现 CoDel 状态信息
   546  	start := queue.Stat()
   547  	fmt.Println(start)
   548  
   549  	go func() {
   550  		// 实际消费的地方
   551  		queue.Pop()
   552  	}()
   553  	if err := queue.Push(context.TODO()); err != nil {
   554  		if err == bbr.LimitExceed {
   555  			// todo 处理过载保护错误
   556  		} else {
   557  			// todo 处理其他错误
   558  		}
   559  	}
   560  }
   561  ```
   562  
   563  ## delayed
   564  
   565  > 单机版本的延时任务,利用四叉堆进行实现,可以自定义监控信号,以及监控时间,以及工作协程数量
   566  
   567  ```go
   568  package main
   569  
   570  import "github.com/songzhibin97/gkit/delayed"
   571  
   572  type mockDelayed struct {
   573  	exec int64
   574  }
   575  
   576  func (m mockDelayed) Do() {
   577  }
   578  
   579  func (m mockDelayed) ExecTime() int64 {
   580  	return m.exec
   581  }
   582  
   583  func (m mockDelayed) Identify() string {
   584  	return "mock"
   585  }
   586  
   587  func main() {
   588  	// 创建延时对象
   589  	// delayed.SetSingle() 设置监控信号
   590  	// delayed.SetSingleCallback() 设置信号回调
   591  	// delayed.SetWorkerNumber() 设置工作协程
   592  	// delayed.SetCheckTime() 设置监控时间
   593  	n := delayed.NewDispatchingDelayed()
   594  
   595  	// 添加延时任务
   596  	n.AddDelayed(mockDelayed{exec: 1})
   597  	
   598  	// 强制刷新
   599  	n.Refresh()
   600  	
   601  	// 关闭
   602  	n.Close()
   603  }
   604  
   605  ```
   606  
   607  ## distributed 
   608  
   609  > 分布式任务, 目前后端支持db(gorm),mongodb,redis,调度端支持redis,分布式锁支持redis,包括重试机制,以及延时任务
   610  
   611  
   612  ## downgrade
   613  
   614  > 熔断降级
   615  
   616  ```go
   617  // 与 github.com/afex/hystrix-go 使用方法一致,只是做了抽象封装,避免因为升级对服务造成影响
   618  package main
   619  
   620  import (
   621  	"context"
   622  	"github.com/afex/hystrix-go/hystrix"
   623  	"github.com/songzhibin97/gkit/downgrade"
   624  )
   625  
   626  var fuse downgrade.Fuse
   627  
   628  type RunFunc = func() error
   629  type FallbackFunc = func(error) error
   630  type RunFuncC = func(context.Context) error
   631  type FallbackFuncC = func(context.Context, error) error
   632  
   633  var outCH = make(chan struct{}, 1)
   634  
   635  func mockRunFunc() RunFunc {
   636  	return func() error {
   637  		outCH <- struct{}{}
   638  		return nil
   639  	}
   640  }
   641  
   642  func mockFallbackFunc() FallbackFunc {
   643  	return func(err error) error {
   644  		return nil
   645  	}
   646  }
   647  
   648  func mockRunFuncC() RunFuncC {
   649  	return func(ctx context.Context) error {
   650  		return nil
   651  	}
   652  }
   653  
   654  func mockFallbackFuncC() FallbackFuncC {
   655  	return func(ctx context.Context, err error) error {
   656  		return nil
   657  	}
   658  }
   659  
   660  func main() {
   661  	// 拿到一个熔断器
   662  	fuse = downgrade.NewFuse()
   663  
   664  	// 不设置 ConfigureCommand 走默认配置
   665  	// hystrix.CommandConfig{} 设置参数
   666  	fuse.ConfigureCommand("test", hystrix.CommandConfig{})
   667  
   668  	// Do: 同步执行 func() error, 没有超时控制 直到等到返回,
   669  	// 如果返回 error != nil 则触发 FallbackFunc 进行降级
   670  	err := fuse.Do("do", mockRunFunc(), mockFallbackFunc())
   671  	if err != nil {
   672  		// 处理 error
   673  	}
   674  
   675  	// Go: 异步执行 返回 channel
   676  	ch := fuse.Go("go", mockRunFunc(), mockFallbackFunc())
   677  	select {
   678  	case err = <-ch:
   679  	// 处理错误
   680  	case <-outCH:
   681  		break
   682  	}
   683  
   684  	// GoC: Do/Go 实际上最终调用的就是GoC, Do主处理了异步过程
   685  	// GoC可以传入 context 保证链路超时控制
   686  	fuse.GoC(context.TODO(), "goc", mockRunFuncC(), mockFallbackFuncC())
   687  }
   688  ```
   689  
   690  ## egroup
   691  
   692  > 组件生命周期管理,与sync.ErrorGroup相比,增加了容错机制,防止野生goroutine panic导致系统异常退出
   693  
   694  
   695  ```go
   696  // errorGroup 
   697  // 级联控制,如果有组件发生错误,会通知group所有组件退出
   698  // 声明生命周期管理
   699  
   700  package main
   701  
   702  import (
   703  	"context"
   704  	"fmt"
   705  	"github.com/songzhibin97/gkit/egroup"
   706  	"github.com/songzhibin97/gkit/goroutine"
   707  	"net/http"
   708  	"os"
   709  	"syscall"
   710  	"time"
   711  )
   712  
   713  var admin *egroup.LifeAdmin
   714  
   715  func mockStart() func(ctx context.Context) error {
   716  	return nil
   717  }
   718  
   719  func mockShutdown() func(ctx context.Context) error {
   720  	return nil
   721  }
   722  
   723  type mockLifeAdminer struct{}
   724  
   725  func (m *mockLifeAdminer) Start(ctx context.Context) error {
   726  	return nil
   727  }
   728  
   729  func (m *mockLifeAdminer) Shutdown(ctx context.Context) error {
   730  	return nil
   731  }
   732  
   733  func main() {
   734  	// 默认配置
   735  	//admin = egroup.NewLifeAdmin()
   736  
   737  	// 可供选择配置选项
   738  
   739  	// 设置启动超时时间
   740  	// <=0 不启动超时时间,注意要在shutdown处理关闭通知
   741  	// egroup.SetStartTimeout(time.Second)
   742  
   743  	//  设置关闭超时时间
   744  	//	<=0 不启动超时时间
   745  	// egroup.SetStopTimeout(time.Second)
   746  
   747  	// 设置信号集合,和处理信号的函数
   748  	// egroup.SetSignal(func(lifeAdmin *LifeAdmin, signal os.Signal) {
   749  	//	return
   750  	// }, signal...)
   751  
   752  	admin = egroup.NewLifeAdmin(egroup.SetStartTimeout(time.Second), egroup.SetStopTimeout(time.Second),
   753  		egroup.SetSignal(func(a *egroup.LifeAdmin, signal os.Signal) {
   754  			switch signal {
   755  			case syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT:
   756  				a.Shutdown()
   757  			default:
   758  			}
   759  		}))
   760  
   761  	// 通过struct添加
   762  	admin.Add(egroup.Member{
   763  		Start:    mockStart(),
   764  		Shutdown: mockShutdown(),
   765  	})
   766  
   767  	// 通过接口适配
   768  	admin.AddMember(&mockLifeAdminer{})
   769  
   770  	// 启动
   771  	defer admin.Shutdown()
   772  	if err := admin.Start(); err != nil {
   773  		// 处理错误
   774  		// 正常启动会hold主
   775  	}
   776  }
   777  
   778  func Demo() {
   779  	// 完整demo
   780  	var _admin = egroup.NewLifeAdmin()
   781  
   782  	srv := &http.Server{
   783  		Addr: ":8080",
   784  	}
   785  	// 增加任务
   786  	_admin.Add(egroup.Member{
   787  		Start: func(ctx context.Context) error {
   788  			fmt.Println("http start")
   789  			return goroutine.Delegate(ctx, -1, func(ctx context.Context) error {
   790  				return srv.ListenAndServe()
   791  			})
   792  		},
   793  		Shutdown: func(ctx context.Context) error {
   794  			fmt.Println("http shutdown")
   795  			return srv.Shutdown(context.Background())
   796  		},
   797  	})
   798  	// _admin.Start() 启动
   799  	fmt.Println("error", _admin.Start())
   800  	defer _admin.Shutdown()
   801  }
   802  
   803  ```
   804  
   805  ## encrypt
   806  
   807  > aes加密解密常用方法,包括 padkey填充
   808  
   809  ## errors
   810  
   811  封装一些error处理
   812  
   813  ```go
   814  package main
   815  
   816  import (
   817  	"fmt"
   818  	"net/http"
   819  	"time"
   820  	
   821  	"github.com/songzhibin97/gkit/errors"
   822  )
   823  func main() {
   824  	err := errors.Errorf(http.StatusBadRequest, "原因", "携带信息%s", "测试")
   825  	err2 := err.AddMetadata(map[string]string{"time": time.Now().String()}) // 携带元信息
   826  	// err 是原来的错误 err2 是带有元信息的错误
   827  	fmt.Println(errors.Is(err,err2)) // ture
   828  	// 可以解析err2 来获取更多的信息
   829  	fmt.Println(err2.Metadata["time"]) // meta
   830  }
   831  ```
   832  
   833  ## gctuner
   834  
   835  > go 1.19前优化gc利器
   836  
   837  ```go
   838  package main
   839  
   840  import "github.com/songzhibin97/gkit/gctuner"
   841  
   842  func main() {
   843  	// Get mem limit from the host machine or cgroup file.
   844  	limit := 4 * 1024 * 1024 * 1024
   845  	threshold := uint64(float64(limit) * 0.7)
   846  
   847  	gctuner.Tuning(threshold)
   848  
   849  	// Friendly input
   850  	gctuner.TuningWithFromHuman("1g")
   851  
   852  	// Auto
   853  	// There may be problems with multiple services in one pod.
   854  	gctuner.TuningWithAuto(false) // Is it a container? Incoming Boolean
   855  }
   856  ```
   857  
   858  ## generator
   859  
   860  发号器
   861  
   862  ### snowflake
   863  
   864  雪花算法
   865  
   866  ```go
   867  package main
   868  
   869  import (
   870  	"fmt"
   871  	"github.com/songzhibin97/gkit/generator"
   872  	"time"
   873  )
   874  
   875  func main() {
   876  	ids := generator.NewSnowflake(time.Now(), 1)
   877  	nid, err := ids.NextID()
   878  	if err != nil {
   879  		// 处理错误
   880  	}
   881  	fmt.Println(nid)
   882  }
   883  
   884  ```
   885  
   886  ## goroutine
   887  
   888  > 池化,控制野生goroutine panic导致的异常情况, 可以设置最大容量,闲置时间,巡检时间,停止超时时间,日志对象
   889  
   890  ```go
   891  package main
   892  
   893  import (
   894  	"context"
   895  	"fmt"
   896  	"github.com/songzhibin97/gkit/goroutine"
   897  	"time"
   898  )
   899  
   900  var gGroup goroutine.GGroup
   901  
   902  func mockFunc() func() {
   903  	return func() {
   904  		fmt.Println("ok")
   905  	}
   906  }
   907  
   908  func main() {
   909  	// 默认配置
   910  	//gGroup = goroutine.NewGoroutine(context.TODO())
   911  
   912  	// 可供选择配置选项
   913  
   914  	// 设置停止超时时间
   915  	// goroutine.SetStopTimeout(time.Second)
   916  
   917  	// 设置日志对象
   918  	// goroutine.SetLogger(&testLogger{})
   919  
   920  	// 设置pool最大容量
   921  	// goroutine.SetMax(100)
   922  
   923  	gGroup = goroutine.NewGoroutine(context.TODO(),
   924  		goroutine.SetStopTimeout(time.Second),
   925  		goroutine.SetMax(100),
   926  	)
   927  
   928  	// 添加任务
   929  	if !gGroup.AddTask(mockFunc()) {
   930  		// 添加任务失败
   931  	}
   932  
   933  	// 带有超时控制添加任务
   934  	if !gGroup.AddTaskN(context.TODO(), mockFunc()) {
   935  		// 添加任务失败
   936  	}
   937  
   938  	// 修改 pool最大容量
   939  	gGroup.ChangeMax(1000)
   940  
   941  	// 回收资源
   942  	_ = gGroup.Shutdown()
   943  }
   944  ```
   945  
   946  ## log
   947  
   948  日志相关
   949  
   950  ```go
   951  package main
   952  
   953  import (
   954  	"fmt"
   955  	"github.com/songzhibin97/gkit/log"
   956  )
   957  
   958  type testLogger struct{}
   959  
   960  func (l *testLogger) Print(kv ...interface{}) {
   961  	fmt.Println(kv...)
   962  }
   963  
   964  func main() {
   965  	logs := log.NewHelper(log.DefaultLogger)
   966  	logs.Debug("debug", "v")
   967  	logs.Debugf("%s,%s", "debugf", "v")
   968  	logs.Info("Info", "v")
   969  	logs.Infof("%s,%s", "infof", "v")
   970  	logs.Warn("Warn", "v")
   971  	logs.Warnf("%s,%s", "warnf", "v")
   972  	logs.Error("Error", "v")
   973  	logs.Errorf("%s,%s", "errorf", "v")
   974  	/*
   975  	[debug] message=debugv
   976      [debug] message=debugf,v
   977      [Info] message=Infov
   978      [Info] message=infof,v
   979      [Warn] message=Warnv
   980      [Warn] message=warnf,v
   981      [Error] message=Errorv
   982      [Error] message=errorf,v
   983  	*/
   984  	
   985  	logger := log.DefaultLogger
   986  	logger = log.With(logger, "ts", log.DefaultTimestamp, "caller", log.DefaultCaller)
   987  	logger.Log(log.LevelInfo, "msg", "helloworld")
   988  	// [Info] ts=2021-06-10T13:41:35+08:00 caller=main.go:8 msg=helloworld
   989  }
   990  ```
   991  
   992  ## metrics
   993  
   994  提供指标接口,用于实现监控配置
   995  ```go
   996  package main
   997  
   998  type Counter interface {
   999  	With(lvs ...string) Counter
  1000  	Inc()
  1001  	Add(delta float64)
  1002  }
  1003  
  1004  // Gauge is metrics gauge.
  1005  type Gauge interface {
  1006  	With(lvs ...string) Gauge
  1007  	Set(value float64)
  1008  	Add(delta float64)
  1009  	Sub(delta float64)
  1010  }
  1011  
  1012  // Observer is metrics observer.
  1013  type Observer interface {
  1014  	With(lvs ...string) Observer
  1015  	Observe(float64)
  1016  }
  1017  ```
  1018  
  1019  ## middleware
  1020  
  1021  中间件接口模型定义
  1022  ```go
  1023  package main
  1024  
  1025  import (
  1026  	"context"
  1027  	"fmt"
  1028  	"github.com/songzhibin97/gkit/middleware"
  1029  	)
  1030  
  1031  func annotate(s string) middleware.MiddleWare {
  1032  	return func(next middleware.Endpoint) middleware.Endpoint {
  1033  		return func(ctx context.Context, request interface{}) (interface{}, error) {
  1034  			fmt.Println(s, "pre")
  1035  			defer fmt.Println(s, "post")
  1036  			return next(ctx, request)
  1037  		}
  1038  	}
  1039  }
  1040  
  1041  func myEndpoint(context.Context, interface{}) (interface{}, error) {
  1042  	fmt.Println("my endpoint!")
  1043  	return struct{}{}, nil
  1044  }
  1045  
  1046  var (
  1047  	ctx = context.Background()
  1048  	req = struct{}{}
  1049  )
  1050  
  1051  func main()  {
  1052      e := middleware.Chain(
  1053  		annotate("first"),
  1054  		annotate("second"),
  1055  		annotate("third"),
  1056  	)(myEndpoint)
  1057  
  1058  	if _, err := e(ctx, req); err != nil {
  1059  		panic(err)
  1060  	}
  1061  	// Output:
  1062  	// first pre
  1063  	// second pre
  1064  	// third pre
  1065  	// my endpoint!
  1066  	// third post
  1067  	// second post
  1068  	// first post
  1069  }
  1070  ```
  1071  
  1072  
  1073  ## net
  1074  
  1075  网络相关封装
  1076  
  1077  ### tcp
  1078  ```go
  1079      // 发送数据至对端,有重试机制
  1080      Send(data []byte, retry *Retry) error
  1081  
  1082      // 接受数据
  1083      // length == 0 从 Conn一次读取立即返回
  1084      // length < 0 从 Conn 接收所有数据,并将其返回,直到没有数据
  1085      // length > 0 从 Conn 接收到对应的数据返回
  1086      Recv(length int, retry *Retry) ([]byte, error) 
  1087  
  1088      // 读取一行 '\n'
  1089      RecvLine(retry *Retry) ([]byte, error) 
  1090  
  1091      // 读取已经超时的链接
  1092      RecvWithTimeout(length int, timeout time.Duration, retry *Retry) ([]byte, error) 
  1093  
  1094      // 写入数据给已经超时的链接
  1095      SendWithTimeout(data []byte, timeout time.Duration, retry *Retry) error
  1096  
  1097      // 写入数据并读取返回
  1098      SendRecv(data []byte, length int, retry *Retry) ([]byte, error)
  1099  
  1100      // 将数据写入并读出已经超时的链接
  1101      SendRecvWithTimeout(data []byte, timeout time.Duration, length int, retry *Retry) ([]byte, error)
  1102  ```
  1103  
  1104  
  1105  ## options
  1106  
  1107  选项模式接口
  1108  
  1109  
  1110  ## overload
  1111  
  1112  > 提供过载保护,内部使用bbr算法进行限流
  1113  
  1114  **普通使用**
  1115  
  1116  ```go
  1117  package main
  1118  
  1119  import (
  1120  	"context"
  1121  	"github.com/songzhibin97/gkit/overload"
  1122  	"github.com/songzhibin97/gkit/overload/bbr"
  1123  )
  1124  
  1125  func main() {
  1126  	// 普通使用
  1127  	
  1128  	// 先建立Group
  1129  	group := bbr.NewGroup()
  1130  	// 如果没有就会创建
  1131  	limiter := group.Get("key")
  1132  	f, err := limiter.Allow(context.TODO())
  1133  	if err != nil {
  1134  		// 代表已经过载了,服务不允许接入
  1135  		return
  1136  	}
  1137  	// Op:流量实际的操作类型回写记录指标
  1138  	f(overload.DoneInfo{Op: overload.Success})
  1139  }
  1140  ```
  1141  
  1142  **中间件套用**
  1143  
  1144  ```go
  1145  package main
  1146  
  1147  import (
  1148  	"context"
  1149  	"github.com/songzhibin97/gkit/overload"
  1150  	"github.com/songzhibin97/gkit/overload/bbr"
  1151  )
  1152  
  1153  func main() {
  1154  	// 普通使用
  1155  
  1156  	// 先建立Group
  1157  	group := bbr.NewGroup()
  1158  	// 如果没有就会创建
  1159  	limiter := group.Get("key")
  1160  	f, err := limiter.Allow(context.TODO())
  1161  	if err != nil {
  1162  		// 代表已经过载了,服务不允许接入
  1163  		return
  1164  	}
  1165  	// Op:流量实际的操作类型回写记录指标
  1166  	f(overload.DoneInfo{Op: overload.Success})
  1167  
  1168  	// 建立Group 中间件
  1169  	middle := bbr.NewLimiter()
  1170  
  1171  	// 在middleware中 
  1172  	// ctx中携带这两个可配置的有效数据
  1173  	// 可以通过 ctx.Set
  1174  
  1175  	// 配置获取限制器类型,可以根据不同api获取不同的限制器
  1176  	ctx := context.WithValue(context.TODO(), bbr.LimitKey, "key")
  1177  
  1178  	// 可配置成功是否上报
  1179  	// 必须是 overload.Op 类型
  1180  	ctx = context.WithValue(ctx, bbr.LimitOp, overload.Success)
  1181  
  1182  	_ = middle
  1183  }
  1184  ```
  1185  ## page_token
  1186  > https://google.aip.dev/158 Google Pagination
  1187  > 通过选项模式可以配置自定义最大页值,每一页最大元素数,设置加密秘钥,以及过期时间, page_token 可以有效的防止爬虫,以及翻页攻击,也可以限制接口并发量
  1188  
  1189  
  1190  ```go
  1191  package main
  1192  
  1193  import "github.com/songzhibin97/gkit/page_token"
  1194  
  1195  func main() {
  1196     	n := NewTokenGenerate("test") // 资源唯一标识,以及可传上述选项
  1197  	// 10000 为总数
  1198  	// 生成page_token
  1199  	// start - end 起止地址, tk为next_token
  1200  	start, end, tk, err := n.ProcessPageTokens(10000, 100, "") // 0,100, tk
  1201  	start, end, ntk, err := n.ProcessPageTokens(10000, 100, tk) // 100,200,ntk
  1202  	n.GetIndex(ntk) // 200
  1203  }
  1204  ```
  1205  
  1206  ## parser
  1207  
  1208  提供 `.go`文件转`.pb` 以及 `.pb`转`.go`
  1209  `.go`文件转`.pb` 功能更为丰富,例如提供定点打桩代码注入以及去重识别
  1210  ```go
  1211  package main
  1212  
  1213  import (
  1214  	"fmt"
  1215  	"github.com/songzhibin97/gkit/parse/parseGo"
  1216  	"github.com/songzhibin97/gkit/parse/parsePb"
  1217  )
  1218  
  1219  func main() {
  1220  	pgo, err := parseGo.ParseGo("gkit/parse/demo/demo.api")
  1221  	if err != nil {
  1222  		panic(err)
  1223  	}
  1224  	r := pgo.(*parseGo.GoParsePB)
  1225  	for _, note := range r.Note {
  1226  		fmt.Println(note.Text, note.Pos(), note.End())
  1227  	}
  1228  	// 输出 字符串,如果需要自行导入文件
  1229  	fmt.Println(r.Generate())
  1230  
  1231  	// 打桩注入
  1232  	_ = r.PileDriving("", "start", "end", "var _ = 1")
  1233      
  1234  	// 拆装
  1235  	_ = r.PileDismantle("var _ = 1")
  1236  	
  1237  	ppb, err := parsePb.ParsePb("GKit/parse/demo/test.proto")
  1238  	if err != nil {
  1239  		panic(err)
  1240  	}
  1241  	// 输出 字符串,如果需要自行导入文件
  1242  	fmt.Println(ppb.Generate())
  1243  }
  1244  ```
  1245  
  1246  
  1247  ## registry
  1248  
  1249  > 提供注册发现通用接口,使用通用接口外挂依赖,以及固定的实例结构
  1250  > 服务发现提供了多种算法,常见的subset算法,以及最新的rock_steadier_subset
  1251  
  1252  
  1253  ## restrictor
  1254  
  1255  限流器
  1256  
  1257  ### rate
  1258  
  1259  漏桶
  1260  
  1261  ```go
  1262  package main
  1263  
  1264  import (
  1265  	"context"
  1266  	rate2 "github.com/songzhibin97/gkit/restrictor/rate"
  1267  	"golang.org/x/time/rate"
  1268  	"time"
  1269  )
  1270  
  1271  func main() {
  1272  	// 第一个参数是 r Limit。代表每秒可以向 Token 桶中产生多少 token。Limit 实际上是 float64 的别名
  1273  	// 第二个参数是 b int。b 代表 Token 桶的容量大小。
  1274  	// limit := Every(100 * time.Millisecond);
  1275  	// limiter := rate.NewLimiter(limit, 4)
  1276  	// 以上就表示每 100ms 往桶中放一个 Token。本质上也就是一秒钟产生 10 个。
  1277  
  1278  	// rate: golang.org/x/time/rate
  1279  	limiter := rate.NewLimiter(2, 4)
  1280  
  1281  	af, wf := rate2.NewRate(limiter)
  1282  
  1283  	// af.Allow()bool: 默认取1个token
  1284  	// af.Allow() == af.AllowN(time.Now(), 1)
  1285  	af.Allow()
  1286  
  1287  	// af.AllowN(ctx,n)bool: 可以取N个token
  1288  	af.AllowN(time.Now(), 5)
  1289  
  1290  	// wf.Wait(ctx) err: 等待ctx超时,默认取1个token
  1291  	// wf.Wait(ctx) == wf.WaitN(ctx, 1) 
  1292  	_ = wf.Wait(context.TODO())
  1293  
  1294  	// wf.WaitN(ctx, n) err: 等待ctx超时,可以取N个token
  1295  	_ = wf.WaitN(context.TODO(), 5)
  1296  }
  1297  ```
  1298  ### ratelimite
  1299  
  1300  令牌桶
  1301  
  1302  ```go
  1303  package main
  1304  
  1305  import (
  1306  	"context"
  1307  	"github.com/juju/ratelimit"
  1308  	ratelimit2 "github.com/songzhibin97/gkit/restrictor/ratelimite"
  1309  	"time"
  1310  )
  1311  
  1312  func main() {
  1313  	// ratelimit:github.com/juju/ratelimit
  1314  	bucket := ratelimit.NewBucket(time.Second/2, 4)
  1315  
  1316  	af, wf := ratelimit2.NewRateLimit(bucket)
  1317  	// af.Allow()bool: 默认取1个token
  1318  	// af.Allow() == af.AllowN(time.Now(), 1)
  1319  	af.Allow()
  1320  
  1321  	// af.AllowN(ctx,n)bool: 可以取N个token
  1322  	af.AllowN(time.Now(), 5)
  1323  
  1324  	// wf.Wait(ctx) err: 等待ctx超时,默认取1个token
  1325  	// wf.Wait(ctx) == wf.WaitN(ctx, 1) 
  1326  	_ = wf.Wait(context.TODO())
  1327  
  1328  	// wf.WaitN(ctx, n) err: 等待ctx超时,可以取N个token
  1329  	_ = wf.WaitN(context.TODO(), 5)
  1330  }
  1331  ```
  1332  
  1333  ## structure (常用数据结构)
  1334  
  1335  ### hashset
  1336  
  1337  ```go
  1338  package main
  1339  
  1340  func main() {
  1341  	l := hashset.NewInt()
  1342  
  1343  	for _, v := range []int{10, 12, 15} {
  1344  		l.Add(v)
  1345  	}
  1346  
  1347  	if l.Contains(10) {
  1348  		fmt.Println("hashset contains 10")
  1349  	}
  1350  
  1351  	l.Range(func(value int) bool {
  1352  		fmt.Println("hashset range found ", value)
  1353  		return true
  1354  	})
  1355  
  1356  	l.Remove(15)
  1357  	fmt.Printf("hashset contains %d items\r\n", l.Len())
  1358  }
  1359  ```
  1360  
  1361  ### lscq
  1362  
  1363  ```go
  1364  package main
  1365  
  1366  func main() {
  1367  	l := lscq.NewUint64()
  1368  	
  1369  	ok := l.Enqueue(1)
  1370  	if !ok {
  1371  		panic("enqueue failed")
  1372      }   
  1373  	v, err := l.Dequeue()
  1374  	if err != nil {
  1375  		panic("dequeue failed")
  1376      }
  1377  	fmt.Println("lscq dequeue value:", v)
  1378  }
  1379  ```
  1380  
  1381  ### skipmap 
  1382  
  1383  ```go
  1384  package main
  1385  
  1386  func main() {
  1387  	m := skipmap.NewInt()
  1388  
  1389  	// Correctness.
  1390  	m.Store(123, "123")
  1391  	m.Load(123)
  1392  	m.Delete(123)
  1393  	m.LoadOrStore(123)
  1394  	m.LoadAndDelete(123)
  1395  }
  1396  ```
  1397  
  1398  ### skipset 
  1399  
  1400  ```go
  1401  package main
  1402  func Example() {
  1403  	l := skipset.NewInt()
  1404  
  1405  	for _, v := range []int{10, 12, 15} {
  1406  		if l.Add(v) {
  1407  			fmt.Println("skipset add", v)
  1408  		}
  1409  	}
  1410  
  1411  	if l.Contains(10) {
  1412  		fmt.Println("skipset contains 10")
  1413  	}
  1414  
  1415  	l.Range(func(value int) bool {
  1416  		fmt.Println("skipset range found ", value)
  1417  		return true
  1418  	})
  1419  
  1420  	l.Remove(15)
  1421  	fmt.Printf("skipset contains %d items\r\n", l.Len())
  1422  }
  1423  ```
  1424  
  1425  ### zset 查看对应readme 
  1426  
  1427  ## sys
  1428  ### mutex
  1429      锁相关封装(实现了trylock、重入锁等、重入token锁,还可以获取锁指标数据)
  1430  ```go
  1431  package main
  1432  
  1433  func main() {
  1434  	// 获取锁
  1435      lk := mutex.NewMutex()
  1436      // 尝试获取锁
  1437      if lk.TryLock() {
  1438      	// 获取到锁
  1439      	defer lk.Unlock()
  1440      }
  1441      // 获取失败执行其他逻辑
  1442      
  1443      lk.Count() // 获取等待锁的数量
  1444      
  1445      lk.IsLocked() // 锁是否被持有
  1446      
  1447      lk.IsWoken() // 内部是否有等待者被唤醒
  1448      
  1449      lk.IsStarving() // 是否处于饥饿模式
  1450      
  1451      // 重入锁
  1452      // 在同一个goroutine可以多次获取
  1453      rvlk := mutex.NewRecursiveMutex() 
  1454      rvlk.Lock()
  1455      defer rvlk.Unlock()
  1456      
  1457      // token重入锁
  1458      // 传入相同token 可以实现重入功能
  1459      tklk := mutex.NewTokenRecursiveMutex()
  1460      tklk.Lock(token)
  1461      defer tklk.Unlock(token)
  1462  }
  1463      
  1464  ```
  1465  
  1466  ## ternary
  1467  > 三元表达式的简单实现
  1468  > 可以使用通用版本 **[go-baseutils](https://github.com/songzhibin97/go-baseutils/tree/main/base/bternaryexpr)**
  1469  > 注意不要直接使用空指针进行点运算,因为需要先调用它作为入口,解决办法可以是关闭进入的函数
  1470  
  1471  
  1472  ```go
  1473  package main
  1474  import "github.com/songzhibin97/gkit/ternary"
  1475  
  1476  func main() {
  1477      ternary.ReturnInt(true, 1, 2)  // 1
  1478  }
  1479  ```
  1480  
  1481  ## timeout
  1482  
  1483  > 各个服务间的超时控制(以及处理时间格式的结构体)
  1484  
  1485  ```go
  1486  package main
  1487  
  1488  import (
  1489  	"context"
  1490  	"github.com/songzhibin97/gkit/timeout"
  1491  	"time"
  1492  )
  1493  
  1494  func main() {
  1495  	// timeout.Shrink 方法提供全链路的超时控制
  1496  	// 只需要传入一个父节点的ctx 和需要设置的超时时间,他会帮你确认这个ctx是否之前设置过超时时间,
  1497  	// 如果设置过超时时间的话会和你当前设置的超时时间进行比较,选择一个最小的进行设置,保证链路超时时间不会被下游影响
  1498  	// d: 代表剩余的超时时间
  1499  	// nCtx: 新的context对象
  1500  	// cancel: 如果是成功真正设置了超时时间会返回一个cancel()方法,未设置成功会返回一个无效的cancel,不过别担心,还是可以正常调用的
  1501  	d, nCtx, cancel := timeout.Shrink(context.Background(), 5*time.Second)
  1502  	// d 根据需要判断 
  1503  	// 一般判断该服务的下游超时时间,如果d过于小,可以直接放弃
  1504  	select {
  1505  	case <-nCtx.Done():
  1506  		cancel()
  1507  	default:
  1508  		// ...
  1509  	}
  1510  	_ = d
  1511  }
  1512  ```
  1513  其他(目前,GORM还有一个受支持的相关类型.)
  1514  > timeout.DbJSON // provides some functionality in db json format
  1515  > timeout.DTime // provides some functionality in db 15:04:05 format
  1516  > DateStruct // provides some functionality in db 15:04:05 format Embedded in struct mode
  1517  > Date // provides some functionality in db 2006-01-02 format
  1518  > DateTime // provides some functions in db 2006-01-02 15:04:05 format
  1519  > DateTimeStruct // provides some functions in db 2006-01-02 15:04:05 format Embed mode as struct
  1520  > timeout.Stamp // provides some functionality in db timestamp format
  1521  
  1522  
  1523  
  1524  ```go
  1525  package main
  1526  
  1527  import (
  1528  	"github.com/songzhibin97/gkit/timeout"
  1529  	"gorm.io/driver/mysql"
  1530  	"gorm.io/gorm"
  1531  	"time"
  1532  )
  1533  
  1534  type GoStruct struct {
  1535  	DateTime timeout.DateTime
  1536  	DTime    timeout.DTime
  1537  	Date     timeout.Date
  1538  }
  1539  
  1540  func main() {
  1541  	// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
  1542  	dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  1543  	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
  1544  	if err != nil {
  1545  		panic(err)
  1546  	}
  1547  	db.AutoMigrate(&GoStruct{})
  1548  	db.Create(&GoStruct{
  1549  		DateTime: timeout.DateTime(time.Now()),
  1550  		DTime:    timeout.DTime(time.Now()),
  1551  		Date:     timeout.Date(time.Now()),
  1552  	})
  1553  	v := &GoStruct{}
  1554  	db.Find(v) // 成功查出
  1555  }
  1556  
  1557  ```
  1558  
  1559  
  1560  ## tools
  1561  
  1562  ### bind
  1563  ```go
  1564  
  1565  package main
  1566  
  1567  // 为 gin提供一个全能bind工具
  1568  import (
  1569  	"github.com/songzhibin97/gkit/tools/bind"
  1570  
  1571  	"github.com/gin-gonic/gin"
  1572  )
  1573  
  1574  type Test struct {
  1575  	Json  string `json:"json" form:"json,default=jjjson"`
  1576  	Query string `json:"query" form:"query"`
  1577  }
  1578  
  1579  func main() {
  1580  	r := gin.Default()
  1581  	r.POST("test", func(c *gin.Context) {
  1582  		t := Test{}
  1583  		// url : 127.0.0.1:8080/test?query=query
  1584  		// {
  1585  		//  "json":"json",
  1586  		//  "query":"query"
  1587  		// }
  1588  		// err := c.ShouldBindWith(&t, bind.CreateBindAll(c.ContentType()),bind.)
  1589  		// 自定义binding对象
  1590  		// err := c.ShouldBindWith(&t, bind.CreateBindAll(c.ContentType(),bind.SetSelectorParse([]bind.Binding{})))
  1591  		if err != nil {
  1592  			c.JSON(200, err)
  1593  			return
  1594  		}
  1595  		c.JSON(200, t)
  1596  	})
  1597  	r.Run(":8080")
  1598  }
  1599  ```
  1600  
  1601  ### votodo
  1602  ```go
  1603  package main
  1604  
  1605  import "github.com/songzhibin97/gkit/tools/vto"
  1606  
  1607  type CP struct {
  1608  	Z1 int `default:"1"`
  1609  	Z2 string `default:"z2"`
  1610  }
  1611  
  1612  func main() {
  1613  	c1 := CP{
  1614  		Z1: 22,
  1615  		Z2: "33",
  1616  	}
  1617  	c2 := CP{}
  1618  	c3 := CP{}
  1619  	_ = vto.VoToDo(&c2,&c1)
  1620  	// c2 CP{ Z1: 22, Z2: "33"}
  1621  	// 相同名称相同类型的执行复制
  1622  	// 一定要dst、src 必须传指针类型
  1623  	
  1624  	// v1.1.2 新增default标签
  1625  	_ = vto.VoToDo(&c2,&c3)
  1626  	// c2 CP{ Z1: 1, Z2: "z2"}
  1627  	// 相同名称相同类型的执行复制
  1628  	// 一定要dst、src 必须传指针类型
  1629  	
  1630  }
  1631  ```
  1632  
  1633  ### votodoPlus
  1634  
  1635  增加了字段&tag&默认值
  1636  
  1637  
  1638  ## window
  1639  
  1640  提供指标窗口
  1641  ```go
  1642  package main
  1643  
  1644  import (
  1645  	"fmt"
  1646  	"github.com/songzhibin97/gkit/window"
  1647  	"time"
  1648  )
  1649  func main() {
  1650  	w := window.NewWindow()
  1651  	slice := []window.Index{
  1652  		{Name: "1", Score: 1}, {Name: "2", Score: 2},
  1653  		{Name: "2", Score: 2}, {Name: "3", Score: 3},
  1654  		{Name: "2", Score: 2}, {Name: "3", Score: 3},
  1655  		{Name: "4", Score: 4}, {Name: "3", Score: 3},
  1656  		{Name: "5", Score: 5}, {Name: "2", Score: 2},
  1657  		{Name: "6", Score: 6}, {Name: "5", Score: 5},
  1658  	}
  1659  	/*
  1660  			[{1 1} {2 2}]
  1661  		    [{2 4} {3 3} {1 1}]
  1662  		    [{1 1} {2 6} {3 6}]
  1663  		    [{3 9} {4 4} {1 1} {2 6}]
  1664  		    [{1 1} {2 8} {3 9} {4 4} {5 5}]
  1665  		    [{5 10} {3 9} {2 6} {4 4} {6 6}]
  1666  	*/
  1667  	for i := 0; i < len(slice); i += 2 {
  1668  		w.AddIndex(slice[i].Name, slice[i].Score)
  1669  		w.AddIndex(slice[i+1].Name, slice[i+1].Score)
  1670  		time.Sleep(time.Second)
  1671  		fmt.Println(w.Show())
  1672  	}
  1673  }
  1674  ```
  1675  
  1676  
  1677  ## trace
  1678  链路追踪
  1679  
  1680  ```go
  1681  package main
  1682  
  1683  import (
  1684  	"context"
  1685  	"fmt"
  1686  
  1687  	gtrace "github.com/songzhibin97/gkit/trace"
  1688  	"go.opentelemetry.io/otel/trace"
  1689  )
  1690  
  1691  type _Transport struct {
  1692  }
  1693  
  1694  func (tr *_Transport) Get(key string) string {
  1695  	panic("implement me")
  1696  }
  1697  
  1698  func (tr *_Transport) Set(key string, value string) {
  1699  	panic("implement me")
  1700  }
  1701  
  1702  func (tr *_Transport) Keys() []string {
  1703  	panic("implement me")
  1704  }
  1705  func main() {
  1706  	// trace.WithServer() 服务端使用中间件
  1707  	// trace.WithClient() 客户端使用中间件
  1708  	tracer := gtrace.NewTracer(trace.SpanKindServer)
  1709  	ctx, span := tracer.Start(context.Background(), "使用gkit", &_Transport{})
  1710  	fmt.Println(span)
  1711  	defer tracer.End(ctx, span, "replay", nil)
  1712  }
  1713  ```
  1714  
  1715  ## watching
  1716  
  1717  系统监控(包含cpu、mum、gc、goroutine等窗口监控,在预设波动值后dump pprof)