Go 通道缓冲和死锁

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

Go channel buffering and deadlocks

问题

考虑以下代码块,由于达到缓冲区限制,预计会引发错误:

package main        

import (
	"fmt"
	"time"
)

func main() {

	burstyLimiter := make(chan time.Time, 4)

	for i := 0; i < 5; i++ {
		burstyLimiter <- time.Now()
		fmt.Println("adding to burstyLimiter")
	}

}

但是,当我尝试使用以下完全相同的代码块时,它会阻塞而不是抛出错误。我正在尝试理解这种行为。谢谢你的时间。

package main

import (
	"fmt"
	"time"
)

func main() {

	requests := make(chan int, 5)
	close(requests)

	limiter := time.Tick(time.Millisecond * 200)

	for req := range requests {
		<-limiter
		fmt.Println("request", req, time.Now())
	}

	burstyLimiter := make(chan time.Time, 4)

	for i := 0; i < 5; i++ {
		burstyLimiter <- time.Now()
		fmt.Println("adding to burstyLimiter")
	}
}
英文:

Considering the following code block, it's expected to throw an error due to reaching a the buffer limit:

package main        

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {

	burstyLimiter := make(chan time.Time, 4)

	for i := 0; i &lt; 5; i++ {
		burstyLimiter &lt;- time.Now()
		fmt.Println(&quot;adding to burstyLimiter&quot;)
	}

}

But when I try the exact block with the following, it blocks instead of throwing an error. I am tying to understand this behavior. Thanks for your time.

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {

	requests := make(chan int, 5)
	close(requests)

	limiter := time.Tick(time.Millisecond * 200)

	for req := range requests {
		&lt;-limiter
		fmt.Println(&quot;request&quot;, req, time.Now())
	}

	burstyLimiter := make(chan time.Time, 4)

	for i := 0; i &lt; 5; i++ {
		burstyLimiter &lt;- time.Now()
		fmt.Println(&quot;adding to burstyLimiter&quot;)
	}
}

答案1

得分: 1

当Go运行时发现所有的goroutine都处于死锁状态时,你会遇到一种恐慌:等待某个“内部”事件,这里的“内部”指的是另一个goroutine应该触发它。

这就是你在第一个程序中遇到的情况。

在第二个程序中,你有一个“隐藏”的goroutine,由对time.Tick的调用创建。这个goroutine在一个通道上发送滴答声,但不会在其上阻塞(“通过丢弃滴答声来弥补接收者的慢速”来自文档)。因此,在第二个示例中至少有一个正在运行的goroutine,它偶尔会在外部事件(定时器滴答声)上阻塞,因此从Go运行时死锁检测的角度来看,整个系统并没有死锁。

英文:

You get a panic, when the Go runtime discovers that all goroutines are in a deadlock: waiting for some "internal" event, internal in the sense another goroutine is expected to trigger it.

This is what you get in the first program.

In the second program, you have a "hidden" goroutine, created by the call to time.Tick. This goroutine sends ticks on a channel, but does not block on it ("drops ticks to make up for slow receivers" form the docs). So you have at least one running goroutine in the second example, which occasionally blocks on external event (timer tick), thus the whole system is not deadlocked form the point of view of the Go runtime deadlock detection.

huangapple
  • 本文由 发表于 2016年3月5日 16:30:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/35811907.html
匿名

发表评论

匿名网友

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

确定