Go Resiliency库中timeout实现原理及源码解析(go类库)学会了吗

随心笔谈2年前发布 编辑
165 0
🌐 经济型:买域名、轻量云服务器、用途:游戏 网站等 《腾讯云》特点:特价机便宜 适合初学者用 点我优惠购买
🚀 拓展型:买域名、轻量云服务器、用途:游戏 网站等 《阿里云》特点:中档服务器便宜 域名备案事多 点我优惠购买
🛡️ 稳定型:买域名、轻量云服务器、用途:游戏 网站等 《西部数码》 特点:比上两家略贵但是稳定性超好事也少 点我优惠购买



目录1.go-resiliency简介2.timeout模式3.源码实现如下4.扩展一下

? 今天看到项目里用到了go-resiliency这个库,库整体比较简单,代码量不大。主要实现go中几种常见的模式:

后面分析下这几种模式的实现

– circuit-breaker 熔断器

– semaphore       信号量

– timeout         函数超时

– batching        批处理

– retriable       可重复

先看看模式的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)
//执行takesFiveSecond
if err :=dl.Run(takesFiveSecond); err !=nil {
t.Error(err)
}
//执行takesTwentySecond
if err :=dl.Run(takesTwentySecond); err==ErrTimedOut {
t.Error(err)
}
}

这里先dl :=New(10 * time.Second)创建timeout对象Deadline,可以看到Deadline只有一个变量,就是超时时间。执行函数调用dl.Run(takesFiveSecond),如果调用的函数执行时间大于变量timeout,会返回失败。

type Deadline struct {
timeout time.Duration
}
func New(timeout time.Duration) *Deadline {
return &Deadline{
timeout: timeout,
}
}

Deadline对象只有一个timeout成员变量

Run核心函数:

//1. 可以看到Run函数有一个入参是一个函数,函数的原型为func (<-chan struct{}))error 也就是说我们传入work变量就需要定义一个这个的签名函数。
//2. Run函数返回error,这个返回实际是入参work函数返回的。
//3.为什么work函数变量,要有一个chan了? 这个主要为了能让work函数里来控制,Run提前退出
func (d *Deadline) 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:
}
}()
//这里是判断是否超时常用手法,通过select监听2个chan,一个读取结果,一个为超时定时器。
//如果在timeout时间内未读取到执行结果,就触发time.After返回超时
select {
case ret :=<-result:
return ret
case <-time.After(d.timeout):
close(stopper)
return ErrTimedOut
}
}

Run函数定义:Run(work func(<-chan struct{}) error) error :

可以看到Run函数有一个入参是一个函数,函数的原型为func (<-chan struct{}))error 也就是说我们传入work变量就需要定义一个这个的签名函数。Run函数返回error,这个返回实际是入参work函数返回的。

go语言里超时控制还有其他常用方式吗

对就是context.WithTimeout,让我们使用context.WithTimeout来重新实现上面的对象,只需要修改一个地方

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实现原理及源码解析的文章就介绍到这了,更多相关Go Resiliency库中timeout内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:深入探究Golang中log标准库的使用基于Golang开发一个轻量级登录库/框架深入探究Golang中flag标准库的使用

© 版权声明

相关文章