您的位置:首页 > 科技 > 能源 > go 开发小技巧

go 开发小技巧

2024/11/16 19:17:09 来源:https://blog.csdn.net/qq_37011724/article/details/141646485  浏览:    关键词:go 开发小技巧

一、简介

       本篇文章会介绍go 开发小技巧。

二、go 开发技巧

2.1 Semaphore
type Semaphore chan struct{}func NewSemaphore(maxCount int) Semaphore {return make(chan struct{}, maxCount)
}func (s Semaphore) Acquire() {s <- struct{}{}
}func (s Semaphore) tryAcquire() bool{select {case s <- struct{}{}:default:return false}return true
}func (s Semaphore) Release() {<-s
}
2.2 singleflight

    有点类似react的useMemo hook,会缓存函数结果


type SingleFlight struct {m map[string]*call
}type call struct {sync.Onceres any
}func newSingleFlight() *SingleFlight {return &SingleFlight{m: make(map[string]*call),}
}func (sf *SingleFlight) Do(key string, fn func() (any, error)) (any, error) {if sf.m[key] != nil {return sf.m[key].res, nil}ca := &call{}var err errorca.Once.Do(func() {if res, e := fn(); e == nil {ca.res = reserr = esf.m[key] = ca}})return ca.res, err
}
demo
func main() {var sf = newSingleFlight()var wg sync.WaitGroupvar t = time.Now()for i := 0; i < 10; i++ {wg.Add(1)go func() {res, _ := sf.Do("longFunc", func() (any, error) {time.Sleep(5 * time.Second)return 5, nil})fmt.Println(res)wg.Done()}()}wg.Wait()fmt.Println(time.Since(t))
}
2.3 once

    once 可以用来处理只需要之心一次的结果

var (once     sync.Onceinstance *Config
)func GetConfig() *Config {once.Do(func() {instance = loadConfig()})return instance
}
2.4 error group

   err group 可以在调用线程获取并发执行goroute 的错误

func main() {urls := []string {"https://blog.devtrovert.com","https://example.com",}var g errgroup.Groupfor _, url := range urls {url := url // safe before Go 1.22g.Go(func() error {return fetch(url)})}if err := g.Wait() ; err != nil {log.Fatal(err)}
}
2.5 Pool 

Pool是对象池,可以复用对象

type Pool[T any] struct {internal sync.Pool
}func NewPool[T any](newF func() T) *Pool[T] {return &Pool[T]{internal: sync.Pool{New: func() interface{} {return newF()},},}
}func (p *Pool[T]) Get() T {return p.internal.Get().(T)
}func (p *Pool[T]) Put(v T) {p.internal.Put(v)
}
2.6 error

 1. 自定义error的粒度是类型,例如参数类型错误,可重试错误。

  2.wrap或join。

func readConfig(path string) error {return fmt.Errorf("read config: %w", ErrNotFound)
}func main() {err := readConfig("config.json")if errors.Is(err, ErrNotFound) {fmt.Println("config file not found")}
}

  

func main() {var errs = make([]error, 30)var g sync.WaitGroupfor i := 0; i < 10; i++ {g.Add(1)j := igo func(i int) {errs = append(errs, errors.New(fmt.Sprintf("hello, %d", i)))defer g.Done()}(j)}g.Wait()fmt.Println(errors.Join(errs...))
}

join 将多个错误连接

2.7 defer 
测量函数执行时间
func main() {defer TrackTime(time.Now()) // <--- THIStime.Sleep(500 * time.Millisecond)
}func TrackTime(pre time.Time) time.Duration {elapsed := time.Since(pre)fmt.Println("elapsed:", elapsed)return elapsed
}// elapsed: 501.11125ms
2.8 实现接口判断

interface

type Buffer interface {Write(p []byte) (n int, err error)
}type StringBuffer struct{}

判断StringBuffer 是否实现Buffer

// syntax: var _ <interface> = (*type)(nil)
var _ Buffer = (*StringBuffer)(nil)
2.9 worker pool
package tasksimport "sync"type Worker struct {maxWorker intch        chan func()wg        sync.WaitGroupresMap    map[string]chan any
}func NewWorker(maxWorker int) *Worker {w := &Worker{maxWorker: maxWorker,ch:        make(chan func()),resMap:    make(map[string]chan any),}for i := 0; i < maxWorker; i++ {go func() {for f := range w.ch {w.done(f)}}()}return w
}func (w *Worker) Go(f func()) {w.wg.Add(1)w.ch <- f
}func (w *Worker) Wait() {w.wg.Wait()close(w.ch) // 关闭通道
}func (w *Worker) done(f func()) {defer w.wg.Done()f()
}func (w *Worker) submit(f func() (res any), key string) chan any {w.resMap[key] = make(chan any)funcWrapper := func() {var res = f()w.resMap[key] <- resclose(w.resMap[key] // 关闭通道}w.Go(funcWrapper)return w.resMap[key]
}
2.10 ConcurrentMap
type ConcurrentMap struct {innerMap map[string]anyrwLock   sync.RWMutex
}func (currMap *ConcurrentMap) Get(key string) any {currMap.rwLock.RLock()defer currMap.rwLock.RUnlock()return currMap.innerMap[key]
}func (currMap *ConcurrentMap) Put(key string, value any) {currMap.rwLock.Lock()defer currMap.rwLock.Unlock()currMap.innerMap[key] = value
}func (currMap *ConcurrentMap) PutIfAbsent(key string, supplier func() any) {currMap.rwLock.Lock()defer currMap.rwLock.Unlock()if value := currMap.innerMap[key]; value != nil {return}currMap.innerMap[key] = supplier()
}
func NewCurrMap() *ConcurrentMap {return &ConcurrentMap{innerMap: make(map[string]any),}
}func (currMap *ConcurrentMap) getOrDefault(key string, supplier func() any) any {currMap.rwLock.RLock()defer currMap.rwLock.RUnlock()if value := currMap.innerMap[key]; value != nil {return value}return supplier()
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com