How does the channel buffer work?

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

How does the channel buffer work?

问题

我通过一系列的定义来理解缓冲区是如何工作的,但我还是不明白。下面是一个例子,我改变了缓冲区的值,但我对它的作用一无所知。有人可以根据这个例子向我解释一下,并提供一些测试用例来说明它是如何工作的吗?谢谢。

package main

import (
	"fmt"
	"time"
)

func send(out, finish chan bool) {
	for i := 0; i < 5; i++ {
		out <- true
		time.Sleep(1 * time.Second)
		fmt.Println("Fin d'une écriture")
	}
	finish <- true
	close(out)
}
func recv(in, finish chan bool) {
	for _ = range in {
		fmt.Println("Fin d'une lecture")
		time.Sleep(10 * time.Second)
	}
	finish <- true
}
func main() {
	chanFoo := make(chan bool, 3)
	chanfinish := make(chan bool)
	go send(chanFoo, chanfinish)
	go recv(chanFoo, chanfinish)
	<-chanfinish
	<-chanfinish
}
英文:

I went through a series of definitions to figure out how the buffer works but I just don't get it. Here is an example below, I changed the value of the buffer but I have no clue about what it does. Can some one explain it to me based on this example and provide some test cases of how/why it's working? Thanks.

package main

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

func send(out, finish chan bool) {
	for i := 0; i &lt; 5; i++ {
		out &lt;- true
		time.Sleep(1 * time.Second)
		fmt.Println(&quot;Fin d&#39;une &#233;criture&quot;)
	}
	finish &lt;- true
	close(out)
}
func recv(in, finish chan bool) {
	for _ = range in {
		fmt.Println(&quot;Fin d&#39;une lecture&quot;)
		time.Sleep(10 * time.Second)
	}
	finish &lt;- true
}
func main() {
	chanFoo := make(chan bool, 3)
	chanfinish := make(chan bool)
	go send(chanFoo, chanfinish)
	go recv(chanFoo, chanfinish)
	&lt;-chanfinish
	&lt;-chanfinish
}

答案1

得分: 2

如果一个通道没有缓冲区,那么一次只能发送一个项目。这意味着发送到该通道的代码将被阻塞,直到某个接收器将项目从通道中读取出来。这是一个人为构造的示例:https://play.golang.org/p/HM8jdIFqsN

package main

import (
    "fmt"
)


func main() {
   blocker := make(chan bool)
   nonBlocker := make(chan bool, 5)

   for i := 0; i < 5; i++ {
        nonBlocker <- true
        fmt.Println("我们继续前进")
   }

   go func () {

    for i := 0; i < 5; i++ {
        blocker <- true
        fmt.Println("我们被阻塞,因为通道已满")
   } }()

}

还有很多其他方法可以演示相同的情况,但基本思想是,如果将通道传递给某个 goroutine,并且该通道没有缓冲区,那么发送到通道的 goroutine 将被阻塞,直到接收到发送的项目。使用带缓冲区的通道,只要缓冲区未满,就可以发送。基本上,如果你启动的 goroutine 在执行工作并返回结果时比生成它们的代码快,你可能需要使用带缓冲区的通道来消除瓶颈。

编辑:如果仍然不清楚发生了什么,请看这个示例:https://play.golang.org/p/9SXc4M1to4

package main

import (
    "fmt"
)


func main() {
   blocker := make(chan bool)
   nonBlocker := make(chan bool, 5)

   for i := 0; i < 5; i++ {
        nonBlocker <- true
        fmt.Println("我们继续前进")
   }

   go func () {

    for i := 0; i < 5; i++ {
        blocker <- true
        fmt.Println("现在我们看到这个,因为接收器不断重新打开通道!")
   } }()

   for i := 0; i < 5; i++ {
      <-blocker
   }
}
英文:

If a channel does not have a buffer then only a single item can be sent on it at a time. This means code that sends on it will block until some receiver reads the item out of the channel. Here's a contrived example; https://play.golang.org/p/HM8jdIFqsN
package main

import (
    &quot;fmt&quot;
)


func main() {
   blocker := make(chan bool)
   nonBlocker := make(chan bool, 5)

   for i := 0; i &lt; 5; i++ {
        nonBlocker &lt;- true
        fmt.Println(&quot;We keep going&quot;)
   }

   go func () {

    for i := 0; i &lt; 5; i++ {
        blocker &lt;- true
        fmt.Println(&quot;We block cause that channel is full&quot;)
   } }()

}

There's plenty of other things I could do to demonstrate the same but the basic idea is, if you pass a channel into some goroutine and the channel is not buffered, the goroutine which sends on the channel will block until the item it sent is received. With a buffered channel you can send as long as the buffer isn't at capacity. Basically, if you spin up goroutines which are doing work and returning the results and they're moving faster than the code that spawned them, you may want to use a buffered channel to open up that bottle neck.

EDIT: If it's still not obvious what's happening look at this; https://play.golang.org/p/9SXc4M1to4

package main

import (
    &quot;fmt&quot;
)


func main() {
   blocker := make(chan bool)
   nonBlocker := make(chan bool, 5)

   for i := 0; i &lt; 5; i++ {
        nonBlocker &lt;- true
        fmt.Println(&quot;We keep going&quot;)
   }

   go func () {

    for i := 0; i &lt; 5; i++ {
        blocker &lt;- true
        fmt.Println(&quot;Now we see this cause the reciever keeps opening the channel up again!&quot;)
   } }()

   for i := 0; i &lt; 5; i++ {
      &lt;-blocker
   }
}

huangapple
  • 本文由 发表于 2015年4月23日 05:00:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/29808720.html
匿名

发表评论

匿名网友

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

确定