Home  >  Article  >  Backend Development  >  Can You Select on Both Sending and Receiving Channels in Go, Without Blocking?

Can You Select on Both Sending and Receiving Channels in Go, Without Blocking?

Susan Sarandon
Susan SarandonOriginal
2024-10-26 22:34:31836browse

 Can You Select on Both Sending and Receiving Channels in Go, Without Blocking?

Selecting on Bidirectional Channels for Conditional Sending and Receiving

In Go, it's possible to set up buffered channels for both sending and receiving, allowing selective operations based on their availability. Consider the following scenario:

<code class="go">s := make(chan<- int, 5)
r := make(<-chan int)

We have a buffered send channel s and an unbuffered receive channel r. The question arises: can we select on both channels to determine if r has data or s is not full? This mimics the functionality of the following, but without consuming 100% CPU:

<code class="go">for {
    if len(s) < cap(s) {
        // Send something
    }
    if len(r) > 0 {
        // Receive something
    }
}</code>

Implementing Select with a Default Case

To achieve this, we can utilize the select statement with a default case. In the default case, if neither channel is ready, we temporarily "sleep" the goroutine to avoid unnecessary resource consumption.

<code class="go">s := make(chan<- int, 5)
r := make(<-chan int)

for {
    v := valueToSend() // Value to be sent, evaluated upon each attempt
    select {
    case s <- v:
        fmt.Println("Sent value:", v)
    case vr := <-r:
        fmt.Println("Received:", vr)
    default: // Neither channel is ready, pause briefly
        time.Sleep(time.Millisecond * 1)
    }
}

Why Length and Capacity Checks Are Not Ideal

It's crucial to avoid checking the length or capacity of a channel before attempting to send or receive. This is because the channel's state can change between the time of checking and the actual operation, potentially leading to unexpected blocking. For instance:

<code class="go">if len(r) > 0 {
    // r is ready to receive

    // Other code...

    r <-  // This may block if another goroutine has already received from r!
}</code>

The above is the detailed content of Can You Select on Both Sending and Receiving Channels in Go, Without Blocking?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn