goroutine 并发控制+锁优化

Leoython · · 1076 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

凑篇幅的introduction

这篇文章希望可以跟大家分享一下写go的一些心得
写这个文章主要的原因是Q1 OKR还没完成,手里目前又没有很深度的技术原理干货。只能将就着分享一下平时写代码的经验了(理由来自Kraken)

正文

goroutine的并发数和子任务超时时间控制

在日常操作中,有大量如此操作:枚举一个id数组,并行对每个id做某种增删改除。为了避免因为某个id的不稳定操作(连接数据库,网络异常等)导致的整体效率下降,最常见的写法就是每个元素开一个独立的goroutine去处理。但是这种做法容易造成超高的并发导致拥堵,最终降低了反而降低了整体效率。
所以我写了一个库用来控制goroutine的并发数和子任务的超时时间, 这个库的来源是之前用过的一个node库promise-limit。使用Map或者更好一点的MapWithTimeout,可以控制最高并发数量workNums,和每个子任务允许的操作时间timeout。一个具体例子长这样:

Ids := []int{1, 2, 3}
items := make([]*Item, len(Ids))
err := routine.MapWithTimeout(len(items), 5, time.Second, func(ctx context.Context, i int) {
    item := getItemByID(Ids[i])
    if ctx.Err() == nil {
        items[i] = item
    }
})

具体的原理并不麻烦,就是通过固定数量的worker拿到通道中的数据进行操作,具体实现可以看代码https://github.com/leoython/r...

稍微做点性能优化

细心的同学可以从代码中看到,我并没有使用go原生的mutex,而是自己写一个简单的spin lock.
mutex 需要把等待锁的 goroutine 放置在等待队列,等到锁释放了才唤醒,使用 spin-lock 是利用 gosched 抢占调度主动让出 CPU 并且把当前 goroutine 保存堆栈状态,
另外,其实 mutex 内部也实现了 spin-lock,但是这个内置的 spin-lock 机制只会 spin 几次而已,而且还有其他的限制条件,有兴趣可看下源码:https://github.com/golang/go/blob/97d0505334c71a8d7a1e7431c1e1515c93b59e2b/src/runtime/proc.go#L5321-L5334


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:Leoython

查看原文:goroutine 并发控制+锁优化

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1076 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传