与频道同时写入

我写了一个简短的脚本来同时写一个文件。一个 goroutine 应该将字符串写入文件,而其他 goroutine 应该通过通道将消息发送给它。但是,由于某些非常奇怪的原因,创建了文件,但没有通过通道向其中添加任何消息。


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() {

    wg.Add(2)

    go concurrent(1)

    go concurrent(2)

    wg.Wait()

    close(output)

    printOutput()

}

该printOutput()够程被完全执行,如果我试图写的for循环它实际上进入文件之后的东西。所以这让我认为范围输出可能为空


炎炎设计
浏览 153回答 3
3回答

有只小跳蛙

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

慕码人2483693

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

蝴蝶刀刀

我对这个问题的看法:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "os"&nbsp; &nbsp; "sync")var wg sync.WaitGroupvar output = make(chan string)var donePrinting = make(chan struct{})func concurrent(n uint) {&nbsp; &nbsp; defer wg.Done() // It only makes sense to defer&nbsp; &nbsp; &nbsp;// wg.Done() before you do something.&nbsp; &nbsp; &nbsp;// (like sending a string to the output channel)&nbsp; &nbsp; output <- fmt.Sprint(n)}func printOutput() {&nbsp; &nbsp; f, err := os.OpenFile("output.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; }&nbsp; &nbsp; defer f.Close()&nbsp; &nbsp; for msg := range output {&nbsp; &nbsp; &nbsp; &nbsp; f.WriteString(msg + "\n")&nbsp; &nbsp; }&nbsp; &nbsp; donePrinting <- struct{}{}}func main() {&nbsp; &nbsp; wg.Add(2)&nbsp; &nbsp; go printOutput()&nbsp; &nbsp; go concurrent(1)&nbsp; &nbsp; go concurrent(2)&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(output)&nbsp; &nbsp; <-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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go