如何使这个golang for-select代码工作?

问题

如何使下面的代码在3秒后打印“QUIT”?


法典

package main


import (

    "fmt"

    "time"

)


func main() {

    quit := make(chan struct{})

    tasks := make(chan struct{})


    go func(){

      time.Sleep(1 * time.Second)

      tasks <- struct{}{}

    }()


    go func(){

      time.Sleep(3 * time.Second)

      quit <- struct{}{}

    }()


    for {

        select {

        case <-quit:

            fmt.Println("QUIT")

            return

        case <-tasks:

            fmt.Println("Doing")

            // do some long time jobs more than 10 seconds

            time.Sleep(10 * time.Second)

        }

    }

}

观察

上面的代码打印“正在做”。并休眠 10 秒钟,然后打印“退出”。如何中断这种睡眠,让它在3秒后接收通道并打印“QUIT”?quit


它似乎被 阻止了,并且在 3 秒后不会从通道接收。selectcase tasksquit


慕运维8079593
浏览 86回答 3
3回答

九州编程

为了表示异步任务的结束,关闭通道是一种最佳实践,这对于防止导致各种死锁的许多未使用非常重要。在你的原始代码中,我会写而不是记住,在关闭的不阻塞上读取并始终返回零值,这就是诀窍。close(quite)quit <- struct{}{}无论如何,从这个开始,解决您的问题的一个优雅方法是使用两者和.context.Contexttime.Aftertime.After将帮助您阻止可选的任务集。context.Context更适合处理这种信号。https://play.golang.org/p/ZVsZw3P-YHdpackage mainimport (&nbsp; &nbsp; "context"&nbsp; &nbsp; "log"&nbsp; &nbsp; "time")func main() {&nbsp; &nbsp; log.Println("start")&nbsp; &nbsp; defer log.Println("end")&nbsp; &nbsp; ctx, cancel := context.WithCancel(context.Background())&nbsp; &nbsp; tasks := make(chan struct{})&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(1 * time.Second) // a job&nbsp; &nbsp; &nbsp; &nbsp; tasks <- struct{}{}&nbsp; &nbsp; }()&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(3 * time.Second) // a job&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; }()&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("QUIT")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; case <-tasks:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.Println("Doing")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // do some long time jobs more than 10 seconds&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-time.After(time.Second * 10):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}

智慧大石

使用 [sync.等待组。package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "time")func worker(msg string, duration time.Duration, doing bool, wg *sync.WaitGroup) {&nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; time.Sleep(duration)&nbsp; &nbsp; fmt.Println(msg)&nbsp; &nbsp; if doing {&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(10 * time.Second)&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; msgs := [2]string{"QUIT", "Doing"}&nbsp; &nbsp; durations := [2]time.Duration{3 * time.Second, 1 * time.Second}&nbsp; &nbsp; doing := [2]bool{false, true}&nbsp; &nbsp; for i, msg := range msgs {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go worker(msg, durations[i], doing[i], &wg)&nbsp; &nbsp; }&nbsp; &nbsp; wg.Wait()}

开满天机

第二个作业运行 10 秒,因此它将阻塞该时间的循环,并且在此作业完成之前不会接收发送到通道的信号。quit为了中断耗时的工作,也许你可以把它分成另一个goroutine。像这样的东西可以做到:go func() {&nbsp; for {&nbsp; &nbsp; select {&nbsp; &nbsp; case <-tasks:&nbsp; &nbsp; &nbsp; fmt.Println("Doing")&nbsp; &nbsp; &nbsp; // do some long time jobs more than 10 seconds&nbsp; &nbsp; &nbsp; time.Sleep(10 * time.Second)&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; }&nbsp; &nbsp;}()&nbsp;<-quitfmt.Println("QUIT")
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go