为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕运维8079593 2022-08-24 20:17:33
问题如何使下面的代码在3秒后打印“QUIT”?法典package mainimport (    "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
查看完整描述

3 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

为了表示异步任务的结束,关闭通道是一种最佳实践,这对于防止导致各种死锁的许多未使用非常重要。在你的原始代码中,我会写而不是记住,在关闭的不阻塞上读取并始终返回零值,这就是诀窍。close(quite)quit <- struct{}{}

无论如何,从这个开始,解决您的问题的一个优雅方法是使用两者和.context.Contexttime.After

time.After将帮助您阻止可选的任务集。

context.Context更适合处理这种信号。

https://play.golang.org/p/ZVsZw3P-YHd

package main


import (

    "context"

    "log"

    "time"

)


func main() {

    log.Println("start")

    defer log.Println("end")

    ctx, cancel := context.WithCancel(context.Background())

    tasks := make(chan struct{})


    go func() {

        time.Sleep(1 * time.Second) // a job

        tasks <- struct{}{}

    }()


    go func() {

        time.Sleep(3 * time.Second) // a job

        cancel()

    }()


    for {

        select {

        case <-ctx.Done():

            log.Println("QUIT")

            return

        case <-tasks:

            log.Println("Doing")

            // do some long time jobs more than 10 seconds

            select {

            case <-ctx.Done():

                return

            case <-time.After(time.Second * 10):

            }

        }

    }

}


查看完整回答
反对 回复 2022-08-24
?
智慧大石

TA贡献1946条经验 获得超3个赞

使用 [sync.等待组。


package main


import (

    "fmt"

    "sync"

    "time"

)


func worker(msg string, duration time.Duration, doing bool, wg *sync.WaitGroup) {

    defer wg.Done()

    time.Sleep(duration)


    fmt.Println(msg)


    if doing {

        time.Sleep(10 * time.Second)

    }

}


func main() {


    var wg sync.WaitGroup

    msgs := [2]string{"QUIT", "Doing"}

    durations := [2]time.Duration{3 * time.Second, 1 * time.Second}

    doing := [2]bool{false, true}


    for i, msg := range msgs {

        wg.Add(1)


        go worker(msg, durations[i], doing[i], &wg)

    }


    wg.Wait()

}


查看完整回答
反对 回复 2022-08-24
?
开满天机

TA贡献1786条经验 获得超13个赞

第二个作业运行 10 秒,因此它将阻塞该时间的循环,并且在此作业完成之前不会接收发送到通道的信号。quit


为了中断耗时的工作,也许你可以把它分成另一个goroutine。像这样的东西可以做到:


go func() {

  for {

    select {

    case <-tasks:

      fmt.Println("Doing")

      // do some long time jobs more than 10 seconds

      time.Sleep(10 * time.Second)

    }   

  }   

}() 


<-quit

fmt.Println("QUIT")


查看完整回答
反对 回复 2022-08-24
  • 3 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信