• golang 中的 time 包的 Ticker


    真实的应用场景是:在测试收包的顺序的时候,加了个 tick 就发现丢包了

    那么来看一个应用例子:

    package main
    
    import (
        "fmt"
        "runtime"
        "time"
    )
    
    func init() {
        runtime.GOMAXPROCS(runtime.NumCPU())
    }
    
    func main() {
        ch := make(chan int, 1024)
        go func(ch chan int) {
            for {
                val := <-ch
                fmt.Printf("val:%d
    ", val)
            }
        }(ch)
    
        tick := time.NewTicker(1 * time.Second)
        for i := 0; i < 20; i++ {
            select {
            case ch <- i:
            case <-tick.C:
                fmt.Printf("%d: case <-tick.C
    ", i)
            }    
    
            time.Sleep(200 * time.Millisecond)
        }
        close(ch)
        tick.Stop()
    }

    输出结果如下:

    val:0
    val:1
    val:2
    val:3
    val:4
    val:5
    6: case <-tick.C
    val:7
    val:8
    val:9
    10: case <-tick.C
    val:11
    val:12
    val:13
    val:14
    15: case <-tick.C
    val:16
    val:17
    val:18
    val:19
    

    问题出在这个select里面:

    select {
        case ch <- i:
        case <-tick.C:
          fmt.Printf("%d: case <-tick.C
    ", i)
    }

      [tick.C 介绍说明] 当两个 case 条件都满足的时候,运行时系统会通过一个伪随机的算法决定哪个case将会被执行。所以当 tick.C 条件满足的那个循环,有某种概率造成 ch<-i 没有发送(虽然通道两端没有阻塞,满足发送条件)

     解决方案1:一旦 tick.C 随机的 case 被随机到,就多执行一次 ch<-i (不体面,如果有多个case就不通用了)

    select {
        case ch <- i:
        case <-tick.C:
            fmt.Printf("%d: case <-tick.C
    ", i)
            ch <- i
    }

       解决方案2:将tick.C的case单独放到一个select里面,并加入一个default(保证不阻塞)

    select {
        case ch <- i:
    }
    select {
        case <-tick.C:
            fmt.Printf("%d: case <-tick.C
    ", i)
        default:
    }

    两种解决方案的输出都是希望的结果:

    val:0
    val:1
    val:2
    val:3
    val:4
    5: case <-tick.C
    val:5
    val:6
    val:7
    val:8
    val:9
    10: case <-tick.C
    val:10
    val:11
    val:12
    val:13
    val:14
    15: case <-tick.C
    val:15
    val:16
    val:17
    val:18
    val:19
  • 相关阅读:
    一周随笔--15.10.06
    KVC/KVO总结
    一周随笔--15.9.28
    一周随笔--15.9.21
    CocoaPods使用中的invalid byte sequence in US-ASCII错误
    自定义TabBar
    FMDB配合sqlite使用
    常用第三方库
    LLDB编译器命令
    coreData
  • 原文地址:https://www.cnblogs.com/liang1101/p/7630002.html
Copyright © 2020-2023  润新知