没有将选择中的通道发送值准备好

问题描述 投票:0回答:2
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)
}

the playground here

我已经研究了一天,但仍然无法解释为什么case ch <- 1:尚未准备好,并且选择了默认情况来运行。当然,它会导致死锁!

go deadlock channel goroutine
2个回答
1
投票

来自doc

如果通道未缓冲,发送方将阻塞,直到接收方收到该值为止。如果通道具有缓冲区,则发送方仅阻塞该值,直到将值复制到该缓冲区为止;否则,发送方才阻塞。如果缓冲区已满,则意味着要等到某些接收者检索到一个值。

一种方法是使用它。这是首先生成接收器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上阅读此thread


0
投票

您已经使用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)
}
© www.soinside.com 2019 - 2024. All rights reserved.