不明白为什么函数 testgo() 只返回一半结果?
package main
import (
"sync"
)
var wg sync.WaitGroup
type myStruct struct {
sync.Mutex
text string
}
func main() {
res := testgo()
print(res)
}
func testgo() string {
var ms myStruct
ch := make(chan string)
for j := 0; j < 10; j++ {
wg.Add(1)
go func() {
defer wg.Done()
ch <- "1\n"
}()
}
go func() {
wg.Wait()
close(ch)
}()
for range ch {
ms.Lock()
ms.text += <-ch
ms.Unlock()
}
return ms.text
}
预计输出字符串中有 10 位数字,但实际只得到 5 位。 (https://go.dev/play/p/KzZdTCoHJXa)
为什么?如何解决这个问题?
输出
1
1
1
1
1
要实现一个在程序终止之前接收并打印所有十条消息的工作解决方案,有一些可行的方法。
以下方法希望您知道您的接收者应该收到多少条消息(十条):
var wgSender sync.WaitGroup
var wgReceiver sync.WaitGroup
type myStruct struct {
sync.Mutex
text string
}
func testgo() string {
var ms myStruct
ch := make(chan string)
for j := 0; j < 10; j++ {
wgSender.Add(1)
go func() {
defer wgSender.Done()
ch <- "1\n"
}()
}
for j := 0; j < 10; j++ {
wgReceiver.Add(1)
go func() {
defer wgReceiver.Done()
ms.Lock()
ms.text += <-ch
ms.Unlock()
}()
}
wgSender.Wait()
wgReceiver.Wait()
close(ch)
return ms.text
}
您还可以像这样使用具有更大缓冲区大小的通道,这样您就可以发送高达特定上限的消息。通过这种方式,您可以删除互斥锁,并且只需要为您的发件人提供一个 WaitGroup。接收端将同步传输您(关闭的)频道的内容:
var wgSender sync.WaitGroup
type myStruct struct {
text string
}
func testgo() string {
var ms myStruct
ch := make(chan string, 99)
for j := 0; j < 10; j++ {
wgSender.Add(1)
go func() {
defer wgSender.Done()
ch <- "1\n"
}()
}
wgSender.Wait()
close(ch)
for message := range ch {
ms.text += message
}
return ms.text
}
第三个选项是使用通道大小 1 并使用 select 语句接收,只要您的通道接收消息直到发生超时:
var wgSender sync.WaitGroup
type myStruct struct {
text string
}
func testgo() string {
var ms myStruct
ch := make(chan string)
for j := 0; j < 10; j++ {
wgSender.Add(1)
go func() {
defer wgSender.Done()
ch <- "1\n"
}()
}
timeoutReached := false
for !timeoutReached {
select {
case <-time.After(1 * time.Second):
// timeout occured here, no more sender routines send anything for 1 second
timeoutReached = true
case message := <-ch:
ms.text += message
}
}
wgSender.Wait()
close(ch) // optionally close the channel
return ms.text
}
所有这三种实现都保证在程序终止之前接收并打印所有 10 条消息。希望对你有帮助