Golang 有必要實現 async-await 嗎?
前言
今天在某站上面看到一個大佬解釋 Golang 中的錯誤處理 err !=nil 時,直接用 Javascript 的 async/await 來解釋。async/await 語法糖在 C#, Python 和 Javascript 中是很常見的異步協程寫法,而在 Golang 中則是使用 goroutine 機制。這時習慣或者喜歡 async/await 語法糖的人可能就會有疑問:Golang 有必要實現 async/await 嗎?
async/await 的出現
最初大家寫請求是這樣寫的:
res = http.get("a.com")
res = http.get("b.com")
這樣順序執行,請求速度很慢。
於是有人寫了線程池,支持並行發請求,api 是 callback 風格:
http.get("a.com", function(err,res){
//xxx
})
http.get("b.com", function(err,res){
//xxx
})
但是很快代碼就變成了:
function(){
// xx
http.get("a.com", function(err, res){
// xx
bar(function(){
// xx
foo(function(){
// xx
http.post("b.com", function(err, res){
// xx
})
})
})
})
}
這樣閱讀性非常低
我們希望異步代碼長得像同步代碼,於是又改成:
await http.get("a.com")
await bar()
await foo()
await http.post("b.com")
爲啥總要寫個 await 呢,是否能去掉呢?
http.get("a.com")
bar()
foo()
http.post("b.com")
這樣就又回到了一開始
因爲光有 await 是沒用的,一定要搭配 Promise.all 纔有用:
res1, res2 = await Promise.all(http.get("a.com"), http.get("b.com"))
await bar()
這樣可讀性就變高了
Golang Channel 實現
回到 Golang,同樣實現以上功能:
urls := []string{
"a.com",
"b.com"
}
resChan := make(chan *http.Response)
for _, url := range urls{
go func(url string){
res, _ := http.Get(url)
resChan <- res
}(url)
}
for _, _ = range urls{
res := <- resChan
fmt.Println(res)
}
這樣看來 channel 完全取代了 Promise,所以 Golang 並不需要 async / await。
Golang await 語義的寫法
寫法很多,但是無一例外,所有的阻塞動作都會被調度器截獲,然後把線程資源釋放出去
官方推薦的 channal
ch := make(chan struct{})
x := 0
go func() {
defer close(ch)
x = 1
}()
<-ch // await
fmt.Println(x)
Mutex
x := 0
mx := sync.Mutex{}
mx.Lock()
go func(){
defer mx.Unlock()
x = 1
}()
mx.Lock() // await
fmt.Println(x)
WaitGroup
x := 0
wg := sync.WaitGroup{}
wg.Add(1)
go func(){
defer wg.Done()
x = 1
}()
wg.Wait() // await
fmt.Println(x)
Cond
x := 0
mx := sync.Mutex{}
cond := sync.NewCond(&mx)
go func(){
defer cond.Signal()
x = 1
}()
mx.Lock()
cond.Wait() // await
mx.Unlock()
fmt.Println(x)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/WITYzHWZBlfz4ZE86jtxUw