为什么我的自定义“等待通道超时”不起作用,以及如何使其起作用?

huangapple go评论76阅读模式
英文:

Why is my custom "Timeout waiting on channel" not working and how to make it work?

问题

我正在尝试制作自己的自定义“通道超时”。更准确地说,是其中的time.After函数。换句话说,我正在尝试实现以下代码:

select {
case v := <-c:
    fmt.Println("Value v:", v)
case <-time.After(1 * time.Second):
    fmt.Println("Timeout")
}

但不幸的是,我遇到了一个问题。

我的实现是:

func waitFun(wait int) chan int {
    time.Sleep(time.Duration(wait) * time.Second)

    c := make(chan int)
    c <- wait

    return c
}

func main() {
    c := make(chan int)
    go func() {
        time.Sleep(3 * time.Second)
        c <- 10
    }()

    select {
    case v := <-c:
        fmt.Println("Value v:", v)
    case <-waitFun(1):
        fmt.Println("Timeout")
    }

    time.Sleep(4 * time.Second)
}

出现错误:all goroutines are asleep - deadlock!。我理解在某个时刻,所有的goroutine(主goroutine和通过匿名函数引入的goroutine)都会进入休眠状态,但这是错误的原因还是其他原因?我的意思是,它不是“无限休眠”或“无限等待某些东西”,所以这不是死锁,对吗?此外,使用time.After也会使goroutine进入休眠状态,对吗?我需要做哪些更改才能使程序正常工作?

英文:

I'm trying to make my own custom "Channel Timeout". More precisely, the time.After function inside it. In other words, I'm trying to implement this:

select {
case v := &lt;-c:
	fmt.Println(&quot;Value v: &quot;, v)
case &lt;-time.After(1 * time.Second):
	fmt.Println(&quot;Timeout&quot;)
}

But unfortunately I ran into a problem.

My implementation is:

func waitFun(wait int) chan int {
	time.Sleep(time.Duration(wait) * time.Second)

	c := make(chan int)
	c &lt;- wait

	return c
}

func main() {
	c := make(chan int)
	go func() {
		time.Sleep(3 * time.Second)
		c &lt;- 10
	}()

	select {
	case v := &lt;-c:
		fmt.Println(&quot;Value v: &quot;, v)
	case &lt;-waitFun(1):
		fmt.Println(&quot;Timeout&quot;)
	}

	time.Sleep(4 * time.Second)
}

For some reason this doesn't work. The error is: all goroutines are asleep - deadlock!. I understand that at some point all goroutines (main and the one introduced with an anonymous function) will go to sleep, but is this the reason for the error or something else? I mean, it's not "infinite sleep" or "infinite wait for something", so it's not a dead lock, right? Additionally, using time.After also sleeps goroutines, right? What do I need to change to make my program work correctly?

答案1

得分: 2

select语句在运行时会评估所有的情况,所以这段代码实际上会在开始监听任何通道之前等待waitFun返回。你需要修改waitFun函数,使其立即返回通道:

func waitFun(wait int) chan int {
    c := make(chan int)
    go func() {
       time.Sleep(time.Duration(wait) * time.Second)
       c <- wait
    }()
    return c
}
英文:

select statement will evaluate all cases when it is run, so this code will actually wait for the waitFun to return before it starts listening to any channels. You have to change the waitFun to return the channel immediately:

func waitFun(wait int) chan int {
    c := make(chan int)
    go func() {
       time.Sleep(time.Duration(wait) * time.Second)
       c &lt;- wait
    }()
    return c
}

huangapple
  • 本文由 发表于 2022年12月28日 02:50:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/74933106.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定