dsffds54654
2015-09-19 12:33
浏览 34
已采纳

After time with time.After的行为不像是用代码或计时器超时

I expect the follwoing to functions to behave the same way

func fillChanTimeoutUsingTicker(maxDuration time.Duration, chanSize int) chan string {
    c := make(chan string, chanSize)
    ticker := time.NewTicker(maxDuration)
    for {
        select {
        case <-ticker.C:
            ticker.Stop()
            fmt.Println("Ticker:operation timedout")
            return c
        case c <- "Random message":
        default:
            fmt.Println("Ticker:chan is full")
            return c
        }
    }
}

func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
    c := make(chan string, chanSize)
    for {
        select {
        case <-time.After(maxDuration):
            fmt.Println("time.After:operation timedout")
            return c
        case c <- "Random message":
        default:
            fmt.Println("time.After:chan is full")
            return c
        }
    }
}

calling them as :

    resWithTicker := fillChanTimeoutUsingTicker(time.Duration(1*time.Microsecond), 10000000)
    fmt.Println(len(resWithTicker))
    resWithTimeAfter := fillChanTimeoutUsingTimeAfter(time.Duration(1*time.Microsecond), 10000000)
    fmt.Println(len(resWithTimeAfter))

prints:

Ticker:operation timedout
43979
time.After:chan is full
10000000

i thought that they would behave exactly the same way and i really don't get the huge difference, any thoughts on this?

note also using a timer works as expected like in the ticker function.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • doubeng1278 2015-09-19 14:11
    已采纳

    The problem lies within your code.

    In your first example, you are creating one ticker and use that for timing out.
    In your second example, you create a timer every time you loop:

    case <-time.After(maxDuration):
    

    As can be seen in the library sources, this is equivalent to

    case <- time.NewTimer(maxDuration).C:
    

    If you create a new Ticker/Timer every time you loop (and discard the old one), it will probably never fire.

    So, to get your second example to behave correctly, do it like this (untested):

    func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
        c := make(chan string, chanSize)
        t := time.After(maxDuration)
        for {
            select {
            case <-t:
                fmt.Println("time.After:operation timedout")
                return c
            case c <- "Random message":
            default:
                fmt.Println("time.After:chan is full")
                return c
            }
        }
    }
    
    点赞 打赏 评论

相关推荐 更多相似问题