client-go和golang源码中的技巧( 四 )
<-chan struct{}) func NonSlidingUntilWithContext(ctx context.Context, f func(context.Context), period time.Duration) Until函数每period会调度f函数 , 如果stopCh中有停止信号 , 则退出 。 当程序运行时间超过period时 , 也不会退出调度循环 , 该特性和Ticker相同 。 底层使用Timer实现 。
Until和NonSlidingUntil为一对 , UntilWithContext和NonSlidingUntilWithContext为一对 , 区别只是定时器启动时间点不同 , 可以简单用下图表示:
这两种(带“NonSliding”前缀的)函数在处理正常程序时没有什么区别 , 但在一些场景下会有不同的地方 。 下面例子中使用wait.NonSlidingUntil处理的程序中sleep了2s , 这可以表示程序因为某种原因导致超出正常处理时间 。 此时可以看到结果中的“num 1”和“num 2”是同时调用的
func main(){first := truenum := 0stopCh:=make(chan struct{} )go func() {time.Sleep(time.Second*10)close(stopCh)fmt.Println("done")}()go wait.NonSlidingUntil(func(){if true == first{time.Sleep(time.Second*2)first=false}num = num + 1fmt.Println("num:",num,"time",time.Now())},time.Second*1,stopCh)time.Sleep(time.Second*100)}结果:num: 1 time 2019-07-04 21:05:59.5298524 +0800 CST m=+26.277103101num: 2 time 2019-07-04 21:05:59.554999 +0800 CST m=+26.302249701num: 3 time 2019-07-04 21:06:00.5559679 +0800 CST m=+27.303218601num: 4 time 2019-07-04 21:06:01.5566608 +0800 CST m=+28.303911501将上述程序的wait.NonSlidingUntil替换为wait.Until , 得到如下结果 , 可以看到首次(异常)和第二次(正常)的间隔正好是wait.Until中设置的调度周期 , 即1s 。
ps:大部分场景下两者使用上并没有什么不同 , 毕竟正常情况下程序运行时间必然小于程序调度周期 。 如果需要在程序处理延时的情况下尽快进行下一次调度 , 则选择带”NonSliding“前缀的函数
结果:num: 1 time 2019-07-04 21:09:14.9643889 +0800 CST m=+2.010865201num: 2 time 2019-07-04 21:09:15.9935285 +0800 CST m=+3.040004801num: 3 time 2019-07-04 21:09:16.9956846 +0800 CST m=+4.042160901
- func Forever(f func(), period time.Duration)
- func ExponentialBackoff(backoff Backoff, condition ConditionFunc) error
ExponentialBackoff的首个入参Backoff如下:
- Duration:表示初始的延时时间
- Factor:指数退避的因子
- Jitter:可以看作是偏差因子 , 该值越大 , 每次重试的延时的可选区间越大
- Steps:指数退避的步数 , 可以看作程序的最大重试次数
- Cap:用于在Factor非0时限制最大延时时间和最大重试次数 , 为0表示不限制最大延时时间
type Backoff struct {// The initial duration.Duration time.Duration// Duration is multiplied by factor each iteration. Must be greater// than or equal to zero.Factor float64// The amount of jitter applied each iteration. Jitter is applied after// cap.Jitter float64// The number of steps before duration stops changing. If zero, initial// duration is always used. Used for exponential backoff in combination// with Factor.Steps int// The returned duration will never be greater than cap *before* jitter// is applied. The actual maximum cap is `cap * (1.0 + jitter)`.Cap time.Duration}第二个参数ConditionFunc表示运行的函数 , 返回的bool值表示该函数是否执行成功 , 如果执行成功则会退出指数退避type ConditionFunc func() (done bool, err error)下面做几组测试:=> 当Factor和Jitter都为0时 , 可以看到调度周期是相同的 , 即Duration的值(1s) 。
import ("fmt""k8s.io/apimachinery/pkg/util/wait""time")func main(){var DefaultRetry = wait.Backoff{Steps:5,Duration: 1 * time.Second,Factor:0,Jitter:0,}fmt.Println(wait.ExponentialBackoff(DefaultRetry,func() (bool, error){fmt.Println(time.Now())return false,nil}))}结果:2019-07-05 10:17:33.9610108 +0800 CST m=+0.0798311012019-07-05 10:17:34.961132 +0800 CST m=+1.0799523012019-07-05 10:17:35.961512 +0800 CST m=+2.0803323012019-07-05 10:17:36.9625144 +0800 CST m=+3.0813347012019-07-05 10:17:37.9636334 +0800 CST m=+4.082453701timed out waiting for the condition=> 先看Jitter对duration的影响 , Jitter(duration, b.Jitter)的计算方式如下 , 如果入参的Factor为0 , 而Jitter非0 , 则将Factor调整为1 。 rand.Float64()为[0.0,1.0)的伪随机数 。将Jitter调整为0.5 , 根据下面计算方式预期duration为[1s,1.5s) 。 运行程序得出如下结果 , 观察可以发现 , duration大概是1.4s
if maxFactor <= 0.0 {maxFactor = 1.0}wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
- 中国|浅谈5G移动通信技术的前世和今生
- 芯片|华米GTS2mini和红米手表哪个好 参数功能配置对比
- 桌面|日常使用的软件及网站分享 篇一:几个动态壁纸软件和静态壁纸网站:助你美化你的桌面
- 二维码|村网通?澳大利亚一州推出疫情追踪二维码 还考虑采用人脸识别和地理定位
- 不到|苹果赚了多少?iPhone12成本不到2500元,华为和小米的利润呢?
- 机器人|网络里面的假消息忽悠了非常多的小喷子和小机器人
- 华为|骁龙870和骁龙855区别都是7nm芯片吗 性能对比评测
- 花15.5亿元与中粮包装握手言和 加多宝离上市又进一步?|15楼财经 | 清远加多宝
- 和谐|人民日报海外版今日聚焦云南西双版纳 看科技如何助力人象和谐
- 内容|浅谈内容行业的一些规律和壁垒,聊聊电商平台孵化小红书难点(外部原因)
