3 回答

TA贡献1824条经验 获得超8个赞
你需要从输出通道中取出一些东西,因为它被阻塞,直到有东西移除你放在它上面的东西。
不是唯一/最好的方法,但是:我移到printOutput()其他函数之上并将其作为 go 例程运行,它可以防止死锁。
package main
import (
"fmt"
"os"
"sync"
)
var wg sync.WaitGroup
var output = make(chan string)
func concurrent(n uint64) {
output <- fmt.Sprint(n)
defer wg.Done()
}
func printOutput() {
f, err := os.OpenFile("output.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer f.Close()
for msg := range output {
f.WriteString(msg + "\n")
}
}
func main() {
go printOutput()
wg.Add(2)
go concurrent(1)
go concurrent(2)
wg.Wait()
close(output)
}

TA贡献1860条经验 获得超9个赞
一,为什么你会得到一个空的原因output是因为渠道是blocking两个发送/接收。
根据您的流程,下面的代码片段永远不会到达wg.Done(),因为发送通道期望接收端将数据拉出。这是一个典型的死锁例子。
func concurrent(n uint64) {
output <- fmt.Sprint(n) // go routine is blocked until data in channel is fetched.
defer wg.Done()
}
让我们检查一下主要功能:
func main() {
wg.Add(2)
go concurrent(1)
go concurrent(2)
wg.Wait() // the main thread will be waiting indefinitely here.
close(output)
printOutput()
}

TA贡献1801条经验 获得超8个赞
我对这个问题的看法:
package main
import (
"fmt"
"os"
"sync"
)
var wg sync.WaitGroup
var output = make(chan string)
var donePrinting = make(chan struct{})
func concurrent(n uint) {
defer wg.Done() // It only makes sense to defer
// wg.Done() before you do something.
// (like sending a string to the output channel)
output <- fmt.Sprint(n)
}
func printOutput() {
f, err := os.OpenFile("output.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer f.Close()
for msg := range output {
f.WriteString(msg + "\n")
}
donePrinting <- struct{}{}
}
func main() {
wg.Add(2)
go printOutput()
go concurrent(1)
go concurrent(2)
wg.Wait()
close(output)
<-donePrinting
}
每个concurrent函数将从等待组中扣除。
两个concurrentgoroutine 完成后,wg.Wait()将解除阻塞,并执行下一条指令 ( close(output))。在关闭通道之前,您必须等待两个 goroutine 完成。相反,如果您尝试以下操作:
go printOutput()
go concurrent(1)
go concurrent(2)
close(output)
wg.Wait()
您可能会close(output)在任何一个concurrentgoroutine 结束之前执行指令。如果通道在并发 goroutine 运行之前关闭,它们将在运行时崩溃(在尝试写入关闭的通道时)。
那么,如果您不等待printOutput()goroutine 完成,您实际上可以main()在printOutput()有机会完成对其文件的写入之前退出。
因为我想printOutput()在退出程序之前等待goroutine 完成,所以我还创建了一个单独的通道来表示printOutput()已经完成。
的<-donePrinting指令块,直到main接收的东西在donePrinting信道。一旦main收到任何东西(甚至是printOutput()发送的空结构),它就会解除阻塞并运行到结论。
https://play.golang.org/p/nXJoYLI758m
- 3 回答
- 0 关注
- 152 浏览
添加回答
举报