英文:
GoRoutines, Channels with WaitGroup unexpected output
问题
我看了一些我很久以前写的代码,当时可能是在 go1.3 发布的时候(我可能记错了)。下面的代码以前能够按预期工作,但是现在,自从我将 go
更新到当前的主版本(go version devel +bd1efd5 Fri Jul 31 16:11:21 2015 +0000 darwin/amd64)之后,最后的输出消息 c <- "FUNC 1 DONE"
没有打印出来,在 play.golang.org
上的代码按预期工作。我做错了什么,还是这是一个 bug?
package main
import (
"fmt"
"sync"
"time"
)
func test(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 1")
time.Sleep(3 * time.Second)
c <- "FUNC 1 DONE"
}
func test1(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 2")
time.Sleep(2 * time.Second)
c <- "FUNC 2 DONE"
}
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func(c chan string) {
for txt := range c {
fmt.Println(txt)
}
}(ch)
wg.Wait()
}
更新:
我并不是说上面的代码是做这些工作的最佳方式,但是我没有看出任何问题。
同时在 go version go1.4.2 darwin/amd64
上运行将返回预期的输出。
英文:
I looked at some code that I've wrote a long time ago, when go1.3 was released(I might be wrong). CODE HERE
The below code used to work as expected, but now since I've update go
to the current master version(go version devel +bd1efd5 Fri Jul 31 16:11:21 2015 +0000 darwin/amd64), the last output message c <- "FUNC 1 DONE"
is not printed, the code works as it should on play.golang.org
. Did I do something wrong, or this is a bug?
package main
import ("fmt";"sync";"time")
func test(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 1")
time.Sleep(3 * time.Second)
c <- "FUNC 1 DONE"
}
func test1(c chan string, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("EXEC FUNC 2")
time.Sleep(2 * time.Second)
c <- "FUNC 2 DONE"
}
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func(c chan string) {
for txt := range c {
fmt.Println(txt)
}
}(ch)
wg.Wait()
}
UPDATE:
I'm not saying that, the above is the best way of doing those types of work, but I don't see anything wrong with it.
Also running it in go version go1.4.2 darwin/amd64
will return the expected output.
答案1
得分: 7
你的代码一直存在这个 bug。只是偶然间你的程序在 main 函数退出之前成功打印了所有的消息。
为了正确地解决这个问题,我建议你将 wg.Wait()
和通道接收的位置互换,这样你就可以异步关闭通道。这样一来,接收操作将阻塞 main
函数,而通道会在所有发送操作完成后立即关闭。
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func() {
wg.Wait()
close(ch)
}()
for txt := range ch {
fmt.Println(txt)
}
}
希望对你有帮助!
英文:
Your code has always had this bug. It was only by chance that your program managed to print all messages before main exited.
To make this work correctly, I would invert where you have the wg.Wait()
and the channel receives, so you can asynchronously close the channel. This way the receive operations are what is blocking main
, and the channel is closed as soon as all send operations are done.
func main() {
ch := make(chan string)
var wg sync.WaitGroup
wg.Add(2)
go test(ch, &wg)
go test1(ch, &wg)
go func() {
wg.Wait()
close(ch)
}()
for txt := range ch {
fmt.Println(txt)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论