我有多个goroutine写入同一通道。如果使用缓冲通道,则可以检索输入。但是,如果使用无缓冲通道,我只能读取大约一半的值:
func testAsyncFunc2() {
ch := make(chan int,10)
fmt.Println("testAsyncFunc2")
wg.Add(10)
for i :=0; i < 10; i++ {
go sender3(ch, i)
wg.Done()
}
receiver3(ch)
close(ch)
wg.Wait()
}
这是接收器功能:
func receiver3(ch chan int) {
for {
select {
case <-ch:
fmt.Println(<-ch)
default:
fmt.Println("Done...")
return
}
}
}
发件人功能:
func sender3(ch chan int, i int) {
ch <- i
}
输出:
testAsyncFunc 2 0 4 6 8 2完成...
虽然我希望得到10个号码。
答案 0 :(得分:3)
选择默认值不能以您认为的方式工作。如果选择块具有默认情况,则在其他情况下都无法读取的情况下,它将立即选择它。
这意味着您的Receiver3很可能会遇到默认情况。
答案 1 :(得分:1)
如果未创建缓冲通道,则代码将返回错误,原因是该通道在发送所有值之前已关闭。
请勿关闭通道并等待执行例程完成。如果要关闭通道,请在接收器执行例程中接收到通道上发送的所有值后关闭。
fmt.Println("testAsyncFunc2")
for i :=0; i < 10; i++ {
wg.Add(1)
go sender3(ch, i)
}
receiver3(ch)
close(ch) // this will close the channels before all the values sent on it will be received.
wg.Wait()
还有另一件事要注意,在for循环内启动go例程后,在减少计数器的同时将等待组的计数器增加到10,这是错误的。完成执行后,应减少sender go例程中的等待组计数器。
func sender(ch chan int, int){
defer wg.Done()
}
在for循环中,选择默认条件将在接收到通道上发送的所有值之前运行,这就是为什么所有发送的值都不会打印的原因。因为当通道上没有值发送时,循环将返回。
func receiver3(ch chan int) {
for {
select {
case <-ch:
fmt.Println(<-ch)
default: // this condition will run when value is not available on the channel.
fmt.Println("Done...")
return
}
}
}
创建一个go例程以关闭通道,并等待发送者go例程完成。因此,下面的代码将等待所有执行例程完成通道上的值发送,然后关闭通道:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
ch := make(chan int)
fmt.Println("testAsyncFunc2")
for i := 0; i < 10; i++ {
wg.Add(1)
go sender(ch, i)
}
receiver3(ch)
go func() {
defer close(ch)
wg.Wait()
}()
}
func receiver3(ch <-chan int) {
for i := 0; i < 10; i++ {
select {
case value, ok := <-ch:
if !ok {
ch = nil
}
fmt.Println(value)
}
if ch == nil {
break
}
}
}
func sender(ch chan int, i int) {
defer wg.Done()
ch <- i
}
输出
testAsyncFunc2
9
0
1
2
3
4
5
6
7
8
Go playground上的工作代码