Go Resiliency庫中timeout實現(xiàn)原理及源碼解析
1.go-resiliency簡介
? 今天看到項目里用到了go-resiliency這個庫,庫整體比較簡單,代碼量不大。主要實現(xiàn)go中幾種常見的模式:
后面分析下這幾種模式的實現(xiàn)
- circuit-breaker 熔斷器
- semaphore 信號量
- timeout 函數(shù)超時
- batching 批處理
- retriable 可重復
2.timeout模式
先看看模式的test用例
import (
"errors"
"testing"
"time"
)
func takesFiveSecond(stopper <-chan struct{}) error {
time.Sleep(5 * time.Second)
return nil
}
func takesTwentySecond(stopper <-chan struct{}) error {
time.Sleep(20 * time.Second)
return nil
}
func TestDeadline(t *testing.T) {
dl := New(10 * time.Second)
//執(zhí)行takesFiveSecond
if err := dl.Run(takesFiveSecond); err != nil {
t.Error(err)
}
//執(zhí)行takesTwentySecond
if err := dl.Run(takesTwentySecond); err == ErrTimedOut {
t.Error(err)
}
}- 這里先dl := New(10 * time.Second)創(chuàng)建timeout對象Deadline,可以看到Deadline只有一個變量,就是超時時間。
- 執(zhí)行函數(shù)調(diào)用dl.Run(takesFiveSecond),如果調(diào)用的函數(shù)執(zhí)行時間大于變量timeout,會返回失敗。
3.源碼實現(xiàn)如下
type Deadline struct {
timeout time.Duration
}
func New(timeout time.Duration) *Deadline {
return &Deadline{
timeout: timeout,
}
}Deadline對象只有一個timeout成員變量
Run核心函數(shù):
//1. 可以看到Run函數(shù)有一個入?yún)⑹且粋€函數(shù),函數(shù)的原型為func (<-chan struct{}))error 也就是說我們傳入work變量就需要定義一個這個的簽名函數(shù)。
//2. Run函數(shù)返回error,這個返回實際是入?yún)ork函數(shù)返回的。
//3.為什么work函數(shù)變量,要有一個chan了? 這個主要為了能讓work函數(shù)里來控制,Run提前退出
func (d *Deadline) Run(work func(<-chan struct{}) error) error {
result := make(chan error)
stopper := make(chan struct{})
//啟動一個協(xié)程
go func() {
value := work(stopper)
select {
case result <- value:
case <-stopper:
}
}()
//這里是判斷是否超時常用手法,通過select監(jiān)聽2個chan,一個讀取結果,一個為超時定時器。
//如果在timeout時間內(nèi)未讀取到執(zhí)行結果,就觸發(fā)time.After返回超時
select {
case ret := <-result:
return ret
case <-time.After(d.timeout):
close(stopper)
return ErrTimedOut
}
}Run函數(shù)定義:Run(work func(<-chan struct{}) error) error :
- 可以看到Run函數(shù)有一個入?yún)⑹且粋€函數(shù),函數(shù)的原型為func (<-chan struct{}))error 也就是說我們傳入work變量就需要定義一個這個的簽名函數(shù)。
- Run函數(shù)返回error,這個返回實際是入?yún)ork函數(shù)返回的。
4.擴展一下
go語言里超時控制還有其他常用方式嗎
對就是context.WithTimeout,讓我們使用context.WithTimeout來重新實現(xiàn)上面的對象,只需要修改一個地方
import (
"context"
"errors"
"time"
)
var ErrTimedOut = errors.New("timed out waiting for function to finish")
type ContextTimeOut struct {
timeout time.Duration
}
// New constructs a new Deadline with the given timeout.
func New(timeout time.Duration) *ContextTimeOut {
return &ContextTimeOut{
timeout: timeout,
}
}
func (d *ContextTimeOut) Run(work func(<-chan struct{}) error) error {
result := make(chan error)
stopper := make(chan struct{})
go func() {
value := work(stopper)
select {
case result <- value:
case <-stopper:
}
}()
ctx, _ := context.WithTimeout(context.Background(), d.timeout)
select {
case ret := <-result:
return ret
case <-ctx.Done():
close(stopper)
return ErrTimedOut
}
}到此這篇關于Go Resiliency庫中timeout實現(xiàn)原理及源碼解析的文章就介紹到這了,更多相關Go Resiliency庫中timeout內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go語言如何在Web服務中實現(xiàn)優(yōu)雅關機
在這篇文章中,我們將通過一個簡單的例子來演示如何在 Go 語言中使用 Gin 框架實現(xiàn)優(yōu)雅關機,感興趣的小伙伴可以跟隨小編一起學習一下2024-11-11
使用golang腳本基于kubeadm創(chuàng)建新的token(問題分析)
這篇文章主要介紹了使用golang腳本基于kubeadm創(chuàng)建新的token(問題分析),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-10-10
golang如何實現(xiàn)mapreduce單進程版本詳解
這篇文章主要給大家介紹了關于golang如何實現(xiàn)mapreduce單進程版本的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-01-01
golang提示dial?tcp?172?.217.163.49:443:?connectex:?A?con
這篇文章主要為大家介紹了golang提示dial?tcp?172?.217.163.49:443:?connectex:?A?connection?attempt?failed解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07

