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选择为运行。当然会造成死锁!
您已使用 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)
}
来自doc:
If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.
一种方法是使用它。这是首先生成的接收器 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)
}
此外,请务必在 Whosebug
上阅读此 thread
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选择为运行。当然会造成死锁!
您已使用 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)
}
来自doc:
If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.
一种方法是使用它。这是首先生成的接收器 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)
}
此外,请务必在 Whosebug
上阅读此 thread