這篇文章但願能夠跟你們分享一下寫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