当前位置: 首页 > article >正文

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.Once
	res 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 error
	ca.Once.Do(func() {
		if res, e := fn(); e == nil {
			ca.res = res
			err = e
			sf.m[key] = ca
		}
	})
	return ca.res, err
}
demo
func main() {
	var sf = newSingleFlight()
	var wg sync.WaitGroup
	var 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.Once
    instance *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.Group

    for _, url := range urls {
        url := url // safe before Go 1.22
        g.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.WaitGroup
	for i := 0; i < 10; i++ {
		g.Add(1)
		j := i
		go 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()) // <--- THIS

    time.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 tasks

import "sync"

type Worker struct {
	maxWorker int
	ch        chan func()
	wg        sync.WaitGroup
	resMap    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] <- res
        close(w.resMap[key] // 关闭通道
	}
	w.Go(funcWrapper)
	return w.resMap[key]
}


http://www.kler.cn/news/290712.html

相关文章:

  • 9.4日常记录
  • Git+word记笔记
  • DriveLM的baseline复现
  • 关于edge浏览器登陆CSDN安全验证不跳出验证码
  • 『 Linux 』简单TCP英译汉程序
  • 【Webpack】基本使用方法
  • 【Linux】僵尸进程(第十一篇)
  • Django缓存
  • [论文笔记]Dimensionality Reduction by Learning an Invariant Mapping
  • 深入理解Java虚拟机的类加载机制
  • 无线通信中OFDM符号提前,有啥影响
  • linux 配置 iscsi 存储资源共享
  • html发送邮件的服务器怎么配置?如何设置?
  • GIT使用常见问题
  • 《JavaEE进阶》----7.<SpringMVC实践项目:【登录页面的验证】>
  • JVM:垃圾回收器 垃圾收集器分类 评估GC的性能指标
  • 双向链表
  • python办公自动化:使用`Python-PPTX`自动化与批量处理
  • 从零开始:理解并实践Prompt Flow
  • inotify + rsync 实时同步 ,定时备份
  • Android12上新增jar遇到的问题总结
  • fedora siliverblue adb
  • 为虚拟机配置固定的IP地址(CentOS9)
  • c++162 类的封装和访问
  • 转载【FIR 线性相位系统 最小相位系统 滤波器延迟】
  • 使用Dbeaver 操作 mongodb
  • 「小明赠书活动」第五期“网安三剑客”套系图书《内网渗透技术》《渗透测试技术》《Web应用安全》
  • Luminar Neo for Mac智能图像处理软件【操作简单,轻松上手】
  • LeetCode 热题100-11 滑动窗口的最大值
  • 前端防抖和节流函数的实现原理