这篇文章但愿能够跟你们分享一下写go的一些心得
写这个文章主要的缘由是Q1 OKR还没完成,手里目前又没有很深度的技术原理干货。只能将就着分享一下平时写代码的经验了(理由来自Kraken)node
在平常操做中,有大量如此操做:枚举一个id数组,并行对每一个id作某种增删改除。为了不由于某个id的不稳定操做(链接数据库,网络异常等)致使的总体效率降低,最多见的写法就是每一个元素开一个独立的goroutine去处理。可是这种作法容易形成超高的并发致使拥堵,最终下降了反而下降了总体效率。
因此我写了一个库用来控制goroutine的并发数和子任务的超时时间, 这个库的来源是以前用过的一个node库promise-limit。使用Map或者更好一点的MapWithTimeout,能够控制最高并发数量workNums,和每一个子任务容许的操做时间timeout。一个具体例子长这样:git
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...github
细心的同窗能够从代码中看到,我并无使用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-L5334golang