国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

聊聊并發庫 Conc,你學會了嗎?

開發 項目管理
我們在寫通用庫和框架的時候,都有一個原則,并發控制與業務邏輯分離,背離這個原則肯定做不出通用庫。

上個月 sourcegraph 放出了 conc[1] 并發庫,目標是 better structured concurrency for go, 簡單的評價一下

每個公司都有類似的輪子,與以往的庫比起來,多了泛型,代碼寫起來更優雅,不需要 interface, 不需要運行時 assert, 性能肯定更好

我們在寫通用庫和框架的時候,都有一個原則,并發控制與業務邏輯分離,背離這個原則肯定做不出通用庫

整體介紹

1. WaitGroup 與 Panic

標準庫自帶 sync.WaitGroup 用于等待 goroutine 運行結束,缺點是我們要處理控制部分

圖片

代碼里大量的 wg.Add 與 wg.Done 函數,所以一般封裝成右側的庫

type WaitGroup struct {
wg sync.WaitGroup
pc panics.Catcher
}

// Go spawns a new goroutine in the WaitGroup.
func (h *WaitGroup) Go(f func()) {
h.wg.Add(1)
go func() {
defer h.wg.Done()
h.pc.Try(f)
}()
}

但是如何處理 panic 呢?簡單的可以在閉包 doSomething 運行時增加一個 safeGo 函數,用于捕捉 recover

圖片

原生 Go 要生成大量無用代碼,我司 repo 運動式的清理過一波,也遇到過 goroutine 忘寫 recover 導致的事故。conc 同時提供 catcher 封裝 recover 邏輯,conc.WaitGroup 可以選擇 Wait 重新拋出 panic, 也可以 WaitAndRecover 返回捕獲到的 panic 堆棧信息

func (h *WaitGroup) Wait() {
h.wg.Wait()

// Propagate a panic if we caught one from a child goroutine.
h.pc.Repanic()
}

func (h *WaitGroup) WaitAndRecover() *panics.RecoveredPanic {
h.wg.Wait()

// Return a recovered panic if we caught one from a child goroutine.
return h.pc.Recovered()
}

2. ForEach 與 Map

高級語言很多的基操,在 go 里面很奢侈,只能寫很多繁瑣代碼。conc封裝了泛型版本的 iterator 和 mapper

func process(values []int) {
iter.ForEach(values, handle)
}

func concMap(input []int, f func(int) int) []int {
return iter.Map(input, f)
}

上面是使用例子,用戶只需要寫業務函數 handle. 相比 go1.19 前的版本,泛型的引入,使得基礎庫的編寫更游刃有余

// Iterator is also safe for reuse and concurrent use.
type Iterator[T any] struct {
// MaxGoroutines controls the maximum number of goroutines
// to use on this Iterator's methods.
//
// If unset, MaxGoroutines defaults to runtime.GOMAXPROCS(0).
MaxGoroutines int
}

MaxGoroutines 默認 GOMAXPROCS 并發處理傳參 slice, 也可以自定義,個人認為不合理,默認為 1 最妥

// ForEachIdx is the same as ForEach except it also provides the
// index of the element to the callback.
func ForEachIdx[T any](input []T, f func(int, *T)) { Iterator[T]{}.ForEachIdx(input, f) }

ForEachIdx 在創建 Iterator[T]{} 可以自定義并發度,最終調用 iter.ForEachIdx

// ForEachIdx is the same as ForEach except it also provides the
// index of the element to the callback.
func (iter Iterator[T]) ForEachIdx(input []T, f func(int, *T)) {
......
var idx atomic.Int64
// Create the task outside the loop to avoid extra closure allocations.
task := func() {
i := int(idx.Add(1) - 1)
for ; i < numInput; i = int(idx.Add(1) - 1) {
f(i, &input[i])
}
}

var wg conc.WaitGroup
for i := 0; i < iter.MaxGoroutines; i++ {
wg.Go(task)
}
wg.Wait()
}

ForEachIdx 泛型函數寫得非常好,略去部分代碼。樸素的實現在 for 循環里創建閉包,傳入 idx 參數,然后 wg.Go 去運行。但是這樣會產生大量閉包,我司遇到過大量閉包,造成 heap 內存增長很快頻繁觸發 GC 的性能問題,所以在外層只創建一個閉包,通過 atomic 控制 idx

func Map[T, R any](input []T, f func(*T) R) []R {
return Mapper[T, R]{}.Map(input, f)
}

func MapErr[T, R any](input []T, f func(*T) (R, error)) ([]R, error) {
return Mapper[T, R]{}.MapErr(input, f)
}

Map 與 MapErr 也只是對 ForEachIdx 的封裝,區別是處理 error

3. 各種 Pool 與 Stream

Pool 用于并發處理,同時 Wait 等待任務結束。相比我司現有 concurrency 庫

  • 增加了泛型實現
  • 增加了對 goroutine 的復用
  • 增加并發度設置(我司有,但 conc 實現方式更巧秒)
  • 支持的函數簽名更多

先看一下支持的接口

Go(f func())
Go(f func() error)
Go(f func(ctx context.Context) error)
Go(f func(context.Context) (T, error))
Go(f func() (T, error))
Go(f func() T)
Go(f func(context.Context) (T, error))

理論上這一個足夠用了,傳參 Context, 返回泛型類型與錯誤。

Wait() ([]T, error)

這是對應的 Wait 回收函數,返回泛型結果 []T 與錯誤。具體 Pool 實現由多種組合而來:Pool, ErrorPool, ContextPool, ResultContextPool, ResultPool

func (p *Pool) Go(f func()) {
p.init()

if p.limiter == nil {
// No limit on the number of goroutines.
select {
case p.tasks <- f:
// A goroutine was available to handle the task.
default:
// No goroutine was available to handle the task.
// Spawn a new one and send it the task.
p.handle.Go(p.worker)
p.tasks <- f
}
}
......
}

func (p *Pool) worker() {
// The only time this matters is if the task panics.
// This makes it possible to spin up new workers in that case.
defer p.limiter.release()

for f := range p.tasks {
f()
}
}

復用方式很巧妙,如果處理速度足夠快,沒必要過多創建 goroutine

Stream 用于并發處理 goroutine, 但是返回結果保持順序

type Stream struct {
pool pool.Pool
callbackerHandle conc.WaitGroup
queue chan callbackCh

initOnce sync.Once
}

實現很簡單,queue 是一個 channel, 類型 callbackCh 同樣也是 channel, 在真正派生 goroutine 前按序順生成 callbackCh 傳遞結果

Stream 命名很差,容易讓人混淆,感覺叫 OrderedResultsPool 更理想,整體非常雞肋

超時

超時永遠是最難處理的問題,目前 conc 庫 Wait 函數并沒有提供 timeout 傳參,這就要求閉包內部必須考濾超時,如果添加 timeout 傳參,又涉及 conc 內部庫并發問題題

Wait() ([]T, error)

比如這個返回值,內部 append 到 slice 時是有鎖的,如果 Wait 提前結束了會發生什么?

[]T 拿到的部分結果只能丟棄,返回給上層 timeout error

Context 框架傳遞參數

通用庫很容易做的臃腫,我司并發庫會給閉包產生新的 context, 并繼承所需框架層的 metadata, 兩種實現無可厚非,這些細節總得要處理

小結

代碼量不大,感興趣的可以看看。沒有造輪子的必要,夠用就行,這種庫寫了也沒價值

參考資料

[1]conc: https://github.com/sourcegraph/conc,

責任編輯:武曉燕 來源: 董澤潤的技術筆記
相關推薦

2023-07-10 08:36:21

工具pptword

2024-06-12 08:36:25

2024-03-05 10:09:16

restfulHTTPAPI

2022-12-26 07:48:04

敏捷項目

2023-03-07 07:50:15

Transactio事務代碼

2024-11-08 08:56:01

2022-10-25 07:24:23

數據庫TiDBmysql

2022-07-11 09:00:37

依賴配置文件Mybati

2022-09-26 08:49:11

Java架構CPU

2024-08-19 10:24:14

2022-12-08 10:49:43

2022-04-13 09:01:45

SASSCSS處理器

2024-10-29 08:08:44

2022-03-05 23:29:18

LibuvwatchdogNode.js

2022-12-14 08:31:43

#error編譯命令

2023-06-05 08:36:04

SQL函數RANK()

2023-02-15 08:41:56

多層維表性能寬表

2024-03-04 07:41:18

SpringAOPOOP?

2022-12-27 08:45:00

繪制菜單符號

2022-10-11 08:48:08

HTTP狀態碼瀏覽器
點贊
收藏

51CTO技術棧公眾號

久久免费午夜影院| 5月丁香婷婷综合| 亚洲最大免费| 极品裸体白嫩激情啪啪国产精品| 国产精品欧美日韩一区二区| 亚洲国产欧美在线观看| 日韩一区二区精品视频| 日韩在线短视频| 亚洲欧美日韩精品久久奇米色影视| 国产精品剧情| 欧美一区二区三区视频免费播放| jizzjizz在线观看| 欧美性猛交xxxxx免费看| 天堂中文av| 亚洲一区视频在线| a视频在线看| 一区二区三区在线不卡| 成人福利免费网站| 亚洲欧美国产毛片在线| 交视频在线观看国产| 一区二区三区精品久久久| 1024在线视频| 精品国产999| 国产区av在线| 欧美一区在线视频| 精品三级久久| 一区二区福利视频| 精品一区二区三区四区五区| 久久久免费电影| 日韩在线二区| 免费成人av网站| 国产精品一区二区久久精品| 狠狠v欧美ⅴ日韩v亚洲v大胸 | 亚洲人成小说| 色综合一区二区| 日本免费在线观看| 亚洲国产精品电影| 国产精品蜜月aⅴ在线| 欧美区在线播放| 在线视频你懂| 欧美日韩国产色视频| 精品成人一区二区三区免费视频| 欧美亚洲综合在线| 国产精品25p| 欧美疯狂性受xxxxx另类| 91精彩视频在线观看| 欧美丰满少妇xxxxx高潮对白| 成人在线播放| 国产午夜精品视频免费不卡69堂| 欧美精品影院| 91久久国产综合久久91精品网站| 久久久久久久波多野高潮日日| 在线丝袜欧美日韩制服| 国产视频视频一区| 青青青草网站免费视频在线观看| 精品久久久久久综合日本欧美| www.26天天久久天堂| 国产国语刺激对白av不卡| 亚洲人成人一区二区三区| 成人在线免费观看视频网站| 伊人精品视频| 中国一级大黄大黄大色毛片| 国产精品视频免费| av在线播放av| 久久综合免费视频| 中文字幕日韩一区二区不卡| 亚洲黄色成人久久久| 日韩精品免费一区二区三区| 国产一区二区不卡视频在线观看| 国产精品一级片在线观看| 成年人视频免费看| 欧美va亚洲va香蕉在线| 欧美经典一区| 免费99视频| 中文字幕不卡的av| 麻豆电影在线播放| 久久久久久久久久久免费精品| 国产综合欧美| 国产91在线免费| 欧美日韩成人在线一区| 国产一区一区| 久久伊人一区二区| 亚洲日本护士毛茸茸| 不卡av免费观看| 国产精品爽爽爽| 国产成人综合在线播放| 一本大道香蕉8中文在线视频 | 欧美日韩免费做爰大片| 最近2019中文字幕第三页视频| 综合天堂久久久久久久| 国产日韩一区二区在线| 91精品国产免费| 首页亚洲中字| 免费看黄在线看| 日韩一区二区三区在线视频| 国产欧美一区| 哪个网站能看毛片| 日韩电影在线观看中文字幕 | 亚洲天堂成人| 中文字幕2019第三页| 亚洲免费小视频| 99成人免费视频| 精品剧情v国产在线观看| 亚洲性无码av在线| 日韩精品免费专区| 黄色av网站在线看| 国产女同一区二区| 亚洲婷婷综合久久一本伊一区 | 欧美久久一级| 久久.com| 欧美成人精品h版在线观看| 涩涩av在线| 欧美激情一区二区三区在线视频| 亚洲成av人片一区二区梦乃| 好吊妞视频这里有精品 | 激情图区综合网| 国产剧情在线| 精品国产乱码久久久久久108| 亚洲专区一二三| 日韩高清在线免费观看| 丰满少妇被猛烈进入高清播放| 日韩精品久久久久久福利| 香蕉久久国产| 四虎久久免费| 精品久久精品久久| 欧美美女bb生活片| 亚洲另类黄色| 久操视频在线| 日韩av一级大片| 亚洲电影在线观看| 韩国av一区二区三区| 日韩大尺度黄色| www国产精品内射老熟女| 国产清纯在线一区二区www| 日韩美女在线| 91蝌蚪视频在线观看| 欧美精品在线视频观看| 久久综合色播五月| 大香伊人久久精品一区二区| 8x8x最新地址| 国产一二三视频| 欧美r级在线| 五月综合激情网| 亚洲都市激情| 男女人搞j网站| 国产精品久久久久国产a级| 一区二区三区在线免费播放| 成人亚洲一区二区| 三级视频网站在线| 久久99精品久久久久久三级| 51精品秘密在线观看| 青青草国产精品97视觉盛宴 | 91小视频在线观看| 成人全视频免费观看在线看| 日韩欧美在线播放视频| 欧美亚洲国产视频| 色综合天天综合色综合av| 国产亚洲网站| 成人免费无遮挡| 亚洲黄色av网址| 亚洲伊人久久综合| 日韩一级在线| h视频在线免费观看| 国产精品久久成人免费观看| 爱福利视频一区| 亚洲一区二区综合| 国产日韩亚洲欧美精品| 亚洲wwww| 国产无遮挡又黄又爽免费网站| 91精品久久久久久久久久| 亚洲福利专区| 男男gaygays亚洲| 人妻夜夜添夜夜无码av| 2019亚洲日韩新视频| 欧美午夜精品免费| 国产精品一二三四| 国产欧美一区二区精品久久久| 最新国产在线观看| 久久精品国产sm调教网站演员| 国产精品极品在线| 日韩精品中文字幕在线不卡尤物| 97国产一区二区| 午夜久久tv| 国产剧情一区二区在线观看| 欧美精品久久久久久久久久丰满| 色哺乳xxxxhd奶水米仓惠香| 国产精品电影一区| 国产视频在线观看一区二区| 亚洲综合视频在线| 国产乱理伦片在线观看夜一区| 日本女优一区| 欧美日一区二区三区| 欧美色18zzzzxxxxx| www.av中文字幕| 999在线免费观看视频| 国产精品人妖ts系列视频| 影音先锋久久精品| 久久午夜影院| 久久r热视频| 欧洲日本在线|