假设一个goroutine正在等待两个无缓冲 channel onetwo上的以下选择

select {
    case <-one:
        fmt.Println("read from one")
    case <-two:
        fmt.Println("read from two")
}

而一个goroutine正在等待以下发送
one <- 1

另一个正在等待以下
two <- 2

第一次等待选择意味着 channel onetwo channel 的缓冲区中都有空间,然后保证可以运行哪种select情况?它是确定性的,还是可以在剩下一个未读值的情况下只剩一个 channel 运行。

如果只有一个保证的净输出,那么select是否确保参与select的所有 channel 上所有操作的总顺序?看来效率很低。

例如下面的代码
package main

import (
    "fmt"
    "time"
    "sync"
)

func main() {
    one_net := 0
    two_net := 0
    var mtx = &sync.Mutex{}
    for i := 0; i < 8; i++ {
        one, two := make(chan int), make(chan int)
        go func() { // go routine one
            select {
            case <-one:
                fmt.Println("read from one")

                mtx.Lock()
                one_net++
                mtx.Unlock()
            case <-two:
                fmt.Println("read from two")

                mtx.Lock()
                two_net++
                mtx.Unlock()
            }
        }()
        go func() { // go routine two
            one <- 1

            mtx.Lock()
            one_net--
            mtx.Unlock()

            fmt.Println("Wrote to one")
        }()
        go func() { // go routine three
            two <- 2

            mtx.Lock()
            two_net--
            mtx.Unlock()

            fmt.Println("Wrote to two")
        }()
        time.Sleep(time.Millisecond)
    }
    mtx.Lock()
    fmt.Println("one_net", one_net)
    fmt.Println("two_net", two_net)
    mtx.Unlock()
}

读取次数与写入次数是否甚至不匹配(即one_nettwo_net末尾是否可以不为0)?例如,在select语句正在等待从两个 channel 读取的情况下,然后goroutines 2和3分别执行各自的写操作,但是select仅在这些写操作中选择了一个。

最佳答案



您的问题不精确:How to create a Minimal, Complete, and Verifiable example.例如,
chan.go:

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println()
    for i := 0; i < 8; i++ {
        one, two := make(chan int), make(chan int)
        go func() { // goroutine one
            select {
            case <-one:
                fmt.Println("read from one")
            case <-two:
                fmt.Println("read from two")
            }
            select {
            case <-one:
                fmt.Println("read from one")
            case <-two:
                fmt.Println("read from two")
            }
            fmt.Println()
        }()
        go func() { // goroutine two
            one <- 1
        }()
        go func() { // goroutine three
            two <- 2
        }()
        time.Sleep(time.Millisecond)
    }
}

输出:
$ go run chan.go

read from two
read from one

read from one
read from two

read from one
read from two

read from two
read from one

read from one
read from two

read from two
read from one

read from one
read from two

read from two
read from one

$

您期望什么行为,为什么?



分析您的新示例:

channel 是无缓冲的。例行程序二和例三等待例行程序一。在无缓冲 channel 上的发送将等待,直到有未决的接收。当评估goroutine单选时, channel 1或 channel 2上将有一个待处理的接收。在该 channel 上发送的goroutine(两个或三个)现在可以发送和终止。 Goroutine现在可以在该 channel 上执行接收并终止。作为粗略的goroutine同步机制,我们将goroutine main等待一毫秒,然后将其终止,这将终止所有其他goroutine。它将终止无法发送的goroutine(两个或三个),因为它仍在等待挂起的接收。

您问“读取数量与写入数量是否甚至不匹配(即one_net和two_net末尾是否可以为非0)?例如,在select语句正在等待两个 channel 的读取的情况下,然后goroutines 2和goroutine分别进行各自的写操作,但是选择仅从这些写操作之一中进行。”

goroutines 2和3中只有一个可以发送(写)。将会只有一次(发送)写入和一次(接收)读取。这假定goroutine main在此发生之前没有终止,也就是说,它在一毫秒内发生。

关于select - 选择中多个事物同时发生时的预期行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44745406/

10-15 19:13