An analysis of how to gracefully interrupt timed tasks in the Go language

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Problem description

Now we have created a timer that can do something regularly and turn it off when the execution time expires. For example, you need to collect a week's log, create a timed task to collect logs, execute every 5 seconds, and stop this scheduled task after a week.

Standard library Ticker

Standard library provides the ticker class, the main function is to do something periodically and repeatedly, if there is no set timeout, it will continue to execute. The common wording is as follows:

t := time.NewTicker(3 * time.Second)timeout := time.After(10 * time.Second)go func() {        for {                   <-t.C                 ...        }       }()<-timeout...

注意到这个Ticker对象是无法关闭的, OK, you may find that the ticker class provides the Stop method. But let's see what happens if you turn off T.

package mainimport (        "fmt"        "time")func DoTickerWork(res chan interface{}, timeout <-chan time.Time) {        t := time.NewTicker(3 * time.Second)        go func() {                defer close(res)                i := 1                for {                        <-t.C                        fmt.Printf("start %d th worker\n", i)                        res <- i                        i++                }        }()        <-timeout        t.Stop()        return}func main() {        res := make(chan interface{}, 10000)        timeout := time.After(10 * time.Second)        DoTickerWork(res, timeout)        for v := range res {                fmt.Println(v)        }}

Intuitively, the new goroutine in the process of waiting, the main thread will turn off the timer, there seems to be no bug, but the output is this:

$go run ticker.go start 1 th workerstart 2 th workerstart 3 th worker123fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan receive]:main.main()    /home/gepin.zs/go/src/timer/ticker.go:29 +0xadgoroutine 6 [chan receive]:main.DoTickerWork.func1(0xc42006c060, 0xc4200161c0)    /home/gepin.zs/go/src/timer/ticker.go:14 +0x8ecreated by main.DoTickerWork    /home/gepin.zs/go/src/timer/ticker.go:19 +0x60exit status 2

This indicates that the stop method of the ticker object is the 并没有关掉 ticker channel, but the 阻止了channel的数据写入 goroutine task is still in progress, but the <-t.c has been blocked and there is a deadlock situation. It may be said that call Close (T.C) is possible, but the compilation will error: Cannot close receive-only channel, because T. C is a read-only queue and cannot call the Close method.

How to Solve

Don't think stop can turn off ticker, we can create a new channel with the name done, the cache size is 1,goroutine inside the Select, and then try to get timeout, if it can be fetched, the description has triggered the timeout, and then close ( Done), this time the task ends, the main thread return. The code is as follows:

package mainimport (        "fmt"        "time")func DoTickerWork(res chan interface{}, timeout <-chan time.Time) {        t := time.NewTicker(3 * time.Second)        done := make(chan bool, 1)        go func() {                defer close(res)                i := 1                for {                        select {                        case <-t.C:                                fmt.Printf("start %d th worker\n", i)                                res <- i                                i++                        case <-timeout:                                close(done)                                return                        }                }        }()        <-done        return}func main() {        res := make(chan interface{}, 10000)        timeout := time.After(10 * time.Second)        DoTickerWork(res, timeout)        for v := range res {                fmt.Println(v)        }}

Program returns results

$go run ticker.gostart 1 th workerstart 2 th workerstart 3 th worker123
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.