1 回答

TA貢獻1824條經(jīng)驗 獲得超8個贊
go 源是否意味著上下文并不真正支持調(diào)用其他“長時間運行”函數(shù)的函數(shù)的中止,“鏈?zhǔn)饺∠保?/p>
不可以。任務(wù)可以調(diào)用其他長時間運行的任務(wù),將上下文傳遞到調(diào)用鏈中。這是一種標(biāo)準(zhǔn)做法。如果上下文被取消,嵌套調(diào)用將出錯并沿著調(diào)用堆棧冒泡取消錯誤
有哪些選項可以編寫異步函數(shù),以支持在 .Done() 使用的無限遞歸中取消上下文?
遞歸與幾個采用上下文的嵌套調(diào)用沒有什么不同。如果遞歸調(diào)用采用上下文輸入?yún)?shù)并返回錯誤(即檢查),則遞歸調(diào)用鏈將像一組非遞歸嵌套調(diào)用一樣冒泡取消事件。
首先,讓我們更新您的包裝函數(shù)以支持context.Context:
func longRunningTask(ctx context.Context) <-chan int32 {
r := make(chan int32)
go func() {
defer close(r)
// workload
i, err := someWork(ctx)
if err != nil {
return
}
r <- i
}()
return r
}
然后someWork- 使用睡眠工作負載將如下所示:
func someWork(ctx context.Context) (int32, error) {
tC := time.After(3*time.Second) // fake workload
// we can check this "workload" *AND* the context at the same time
select {
case <-tC:
return rand.Int31n(100), nil
case <-ctx.Done():
return 0, ctx.Err()
}
}
這里要注意的重要一點是,我們可以改變虛假的“工作負載”(time.Sleep),使其成為一個通道——從而通過select語句觀察它和我們的上下文。大多數(shù)工作負載當(dāng)然不是那么簡單……
幸運的是,Go 標(biāo)準(zhǔn)庫完全支持context.Context. 因此,如果您的工作負載包含大量可能長時間運行的 SQL 查詢,則可以為每個查詢傳遞一個上下文。與 HTTP 請求或 gRPC 調(diào)用相同。如果您的工作負載包含這些調(diào)用中的任何一個,則傳入父上下文將導(dǎo)致任何這些潛在的阻塞調(diào)用在上下文被取消時返回錯誤 - 因此您的工作負載將返回取消錯誤,讓調(diào)用者知道什么發(fā)生了。
如果您的工作負載不適合此模型,例如計算大型 Mandelbrot-Set 圖像。在每個像素后檢查取消上下文可能會對性能產(chǎn)生負面影響,因為輪詢選擇不是免費的:
select {
case <-ctx.Done(): // polling select when `default` is included
return ctx.Err()
default:
}
在這種情況下,可以應(yīng)用調(diào)整,如果說像素以 10,000/s 的速率計算 - 每 10,000 個像素輪詢上下文將確保任務(wù)將在取消點后不遲于 1 秒內(nèi)返回。
- 1 回答
- 0 關(guān)注
- 141 瀏覽
添加回答
舉報