Home  >  Article  >  Backend Development  >  Why doesn't Go Channel's buffer limit writes/reads correctly?

Why doesn't Go Channel's buffer limit writes/reads correctly?

WBOY
WBOYforward
2024-02-09 10:30:19423browse

为什么Go Channel的缓冲区不能正确限制写入/读取?

php editor Youzi will answer a common question in this article: "Why does the buffer of Go Channel not limit writing/reading correctly?" In the Go language, Channel It is a mechanism for communication between coroutines. When we use a Channel with a buffer, we expect to be able to control the behavior of the program by limiting the number of write or read operations. However, in fact, the Channel buffer cannot directly limit the number of write/read operations. The causes and solutions to this problem will be elaborated below.

Question content

I am trying to communicate between two go routines using channels. First, I created the integer channel and then passed it as a parameter to a go routine that prints a sequence of numbers from 0 to 10. The output of these programs makes no sense.

This is the main code:

func worker(identifier string, ch chan<- int) {
    fmt.printf("entering worker %s\n", identifier)
    for i := 0; i < 10; i++ {
        fmt.printf("writing %d\n", i)
        ch <- i
    }

    fmt.printf("exiting worker %s\n", identifier)

    close(ch)
}

func main() {
    ch := make(chan int)
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }
}

For this code execution, I got the following output:

entering worker 1
writing 0
writing 1
reading 0
reading 1
writing 2
writing 3
reading 2
reading 3
writing 4
writing 5
reading 4
reading 5
writing 6
writing 7
reading 6
reading 7
writing 8
writing 9
reading 8
reading 9
exiting worker 1

Note that there are two write executions followed by two read executions.

Later, I set a buffer size to achieve the following functions:

func main() {
    ch := make(chan int, 3) // <= buffer
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }

}

Then, we get the following output:

Entering worker 1
Writing 0
Writing 1
Writing 2
Writing 3
Writing 4
Reading 0
Reading 1
Reading 2
Reading 3
Reading 4
Writing 5
Writing 6
Writing 7
Writing 8
Writing 9
Reading 5
Reading 6
Reading 7
Reading 8
Reading 9
Exiting worker 1

Note that now we have 5 write executions and then 5 read executions.

Once we have the code and output, the final question arises: why do these executions behave the way they do? First, isn't it supposed to only read and write one number at a time? Beyond that, why does the second execution read and write 5 numbers each time instead of 3 (since that's the buffer size)?

Workaround

You are confused when a message is printed and when a number is read from or written to the channel.

When a write occurs, the "write" message does not occur. They occur at some point between writes. Likewise, the "reading" message occurs at some point between reads.

Here is one way to arrange the first code snippet, which produces the output shown:

  • Mainly try to read and then block.
  • Staff prints "Writing 0".
  • Worker writes 0, main reads.
  • The worker prints "Writing 1".
  • The worker thread attempted to write 1, but was blocked.
  • Mainly print "Reading 0".
  • The main content is 1.
  • Main print "Reading 1".
  • Mainly try to read and then block.

Control is continuously passed between main and Worker like this, each printing 2 messages before blocking.

Likewise, your second fragment can be arranged like this:

  • Mainly try to read and then block.
  • Worker prints "Writing 0" and sends 0 directly to main.
  • Worker prints "Writing 1" and buffers 1.
  • Worker prints "Writing 2" and buffers 2.
  • Worker prints "Writing 3" and buffers 3.
  • The worker thread prints "Writing 4" and blocks attempts to send 4.
  • main completes the blocked read and prints "Reading 0".
  • main reads the buffered 1 and prints "Reading 1".
  • main reads buffered 2 and prints "Reading 2".
  • main reads the buffered 3 and prints "Reading 3".
  • main reads Worker blocked 4 and prints "Reading 4".
  • Mainly try to read and then block.
  • Execution returns to Worker...

The above is the detailed content of Why doesn't Go Channel's buffer limit writes/reads correctly?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete