欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

go-resiliency源码解析之-timeout

发布时间:2024/1/18 编程问答 42 豆豆
生活随笔 收集整理的这篇文章主要介绍了 go-resiliency源码解析之-timeout 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

go-resiliency源码解析之-timeout

1.go-resiliency简介

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

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

- circuit-breaker 熔断器 - semaphore 信号量 - timeout 函数超时 - 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)//执行takesFiveSecondif err := dl.Run(takesFiveSecond); err != nil {t.Error(err)}//执行takesTwentySecondif err := dl.Run(takesTwentySecond); err == ErrTimedOut {t.Error(err)} }
  • 这里先dl := New(10 * time.Second)创建timeout对象Deadline,可以看到Deadline只有一个变量,就是超时时间。

  • 执行函数调用dl.Run(takesFiveSecond),如果调用的函数执行时间大于变量timeout,会返回失败。

  • 3.源码实现如下

    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 retcase <-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函数返回的。
  • 4.扩展一下,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 retcase <-ctx.Done():close(stopper)return ErrTimedOut} }

    总结

    以上是生活随笔为你收集整理的go-resiliency源码解析之-timeout的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。