這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。我相信你有過調用 API 介面需要使用退避演算法的時候。在 Go 語言現有技術中,有 [github.com/cenkalti/backoff](https://github.com/cenkalti/backoff),[github.com/jpillora/backoff](https://github.com/jpillora/backoff),和其它庫可以使用。我曾經使用過 [github.com/cenkalti/backoff](https://github.com/cenkalti/backoff),但是有一件讓我感到困惑的事:它要求你為操作加上閉包,強制輸入為 func() error 的形式。舉個例子,當你需要一個可以自動重試的函數(如下面的 myFunc 函數),返回 3 個值和一個 error,你需要和範圍鬥智鬥勇。```govar a, b, c Resultbackoff.Retry(func() error {var err errora, b, c, err = myFunc(arg, ...)return err}, backoffObject)```在效能方面,這可能可以忽略不計,但範圍全搞亂了,這個時候你必須要小心,在賦值時不要使用 :=,而是使用 = 來確保獲得正確的值。這是我寫 [github.com/lestrrat-go/backoff](github.com/lestrrat-go/backoff) 庫的主要原因。使用這個庫,你將不得不寫更多的樣板代碼(使用庫需要執行的函數:NewExponential(),Start() 等),但是你不需要實現一個閉包,我發現這樣更加符合 Go 的風格。計算退避期間仍然很難,如果你有更好的演算法,請告訴我。使用 [github.com/lestrrat-go/backoff](github.com/lestrrat-go/backoff) 庫,首先你要建立一個策略對象:```gopolicy := backoff.NewExponential(...)```傳入的參數也會影響到策略,例如配置最大重試次數或者不重試。策略對象可以被多個消費者重用。實際上 backoff 對象是通過調用策略對象的 Start() 方法建立的:```gob, cancel := policy.Start(ctx)```該方法接收一個 context 對象,因此你可以通過父範圍內的釋放操作終止退避演算法。當退避對象 b 不再需要時,cancel 用於釋放資源。退避對象 b 包含兩個方法,Done() 和 Next()。他們都返回一個可以通知我們事件的管道變數。當退避演算法停止時,Done() 變得可讀:(停止的情況)包括父 context 被取消導致退避演算法被取消或者某個條件發生(例如當我們已經重試了 MaxRetries 參數指定的次數時)。當調用過了足夠的時候後,Next() 才變為可讀。在指數級回退的情況下,在調用 Next() 之後,你可能得等 1, 2, 4, 8, 16...(乘以基本區間)。使用這些方法,你的退避方法將看起來就像這樣:```gofunc MyFuncWithRetries(ctx context.Context, ... ) (Result1, Result2, Result3, error) {b, cancel := policy.Start(ctx)defer cancel()for {ret1, ret2, ret3, err := MyFunc(...)if err == nil { // successreturn ret1, ret2, ret3, nil}select {case <-b.Done():return nil, nil, nil, errors.New(`all attempts failed`)case <-b.Next():// continue to beginning of the for loop, execute MyFunc again}}}```使用這種方法的缺點是你需要更多的樣板代碼。優點是你不再需要奇怪的範圍技巧,操作變得更加直接。我認為這是一個關於口味的問題,所以你應該選擇符合你口味或者習慣的庫。這恰好是我想要的庫,希望也對你有協助。編程快樂!
via: https://medium.com/@lestrrat/yak-shaving-with-backoff-libraries-in-go-80240f0aa30c
作者:Daisuke Maki 譯者:gogeof 校對:rxcai
本文由 GCTT 原創編譯,Go語言中文網 榮譽推出
本文由 GCTT 原創翻譯,Go語言中文網 首發。也想加入譯者行列,為開源做一些自己的貢獻嗎?歡迎加入 GCTT!
翻譯工作和譯文發表僅用於學習和交流目的,翻譯工作遵照 CC-BY-NC-SA 協議規定,如果我們的工作有侵犯到您的權益,請及時聯絡我們。
歡迎遵照 CC-BY-NC-SA 協議規定 轉載,敬請在本文中標註並保留原文/譯文連結和作者/譯者等資訊。
文章僅代表作者的知識和看法,如有不同觀點,請樓下排隊吐槽
417 次點擊