繁体   English   中英

在 select 中未准备好向通道发送值

[英]Sending value to a channel is not ready in the select

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}

这里的游乐场

研究了一天还是无法解释为什么case ch <- 1:还没有准备好,选择默认的case运行。 当然,它会导致死锁!

来自文档

如果通道没有缓冲,发送方会阻塞,直到接收方收到该值。 如果通道有缓冲区,发送方只会阻塞,直到值被复制到缓冲区; 如果缓冲区已满,这意味着要等到某个接收器检索到一个值。

一种方法是使用它。 这是接收器 goroutine 首先生成的。 此外,如果接收器尚未准备好,则会选择默认情况。 如果它准备好了,具体案例也将准备好。 如果您多次运行此程序,您可以看到任何一种情况发生。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    // goroutine acts as the reciever
    go func() {
        fmt.Printf("main at %d\n", time.Now().UnixNano())
        fmt.Println(<-ch)
    }()
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()
    time.Sleep(1 * time.Second) // Wait for the goroutines
}

另一种解决方案是使用缓冲通道:

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int, 1)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}

另外,请在stackoverflow上阅读此线程

您已使用未缓冲的 make(chan int) 创建了 Go 通道。 您需要一个缓冲通道(不一定会阻塞),您应该使用 make(chan int, 20) 其中 20 是通道的大小

无缓冲通道的问题在于它们也是同步的,因此它们总是在写入和读取时阻塞。 当缓冲区填满时,缓冲通道也会发生同样的事情。

试试下面的代码

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int, 20)
    go func() {
        fmt.Printf("func at %d\n", time.Now().UnixNano())
        select {
        case ch <- 1:
            fmt.Println("running send")
        default:
            fmt.Println("running default")
        }
    }()

    time.Sleep(100 * time.Millisecond)
    fmt.Printf("main at %d\n", time.Now().UnixNano())
    fmt.Println(<-ch)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM