Go 与频道同步写作

Go 与频道同步写作,go,concurrency,channel,Go,Concurrency,Channel,我写了一个简短的脚本来同时编写文件。 一个goroutine应该将字符串写入一个文件,而其他goroutine应该通过一个通道将消息发送到该文件。 但是,由于一些非常奇怪的原因,创建了文件,但没有通过通道向其添加消息 package main import ( "fmt" "os" "sync" ) var wg sync.WaitGroup var output = make(chan string) func concurrent(n uint64) {

我写了一个简短的脚本来同时编写文件。 一个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()
}
主程序包
进口(
“fmt”
“操作系统”
“同步”
)
var wg sync.WaitGroup
var输出=生成(chan字符串)
func并发(n uint64){

输出当输出通道阻塞时,您需要从输出通道中获取一些内容,直到有内容删除您在其上放置的内容

这不是唯一/最好的方法,而是:我将
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)
}
主程序包
进口(
“fmt”
“操作系统”
“同步”
)
var wg sync.WaitGroup
var输出=生成(chan字符串)
func并发(n uint64){

输出获得空
输出
的原因之一是通道对发送/接收都是阻塞的

根据您的流程,下面的代码片段永远不会到达
wg.Done()
,因为发送通道希望接收端将数据取出。这是一个典型的死锁示例

func concurrent(n uint64) {
    output <- fmt.Sprint(n) // go routine is blocked until data in channel is fetched.
    defer wg.Done()
}


你能修好代码示例吗?正如所写,它不会运行。@Snowman当然!给我一点时间,我会更改类型的variable@Snowman现在应该好多了,在go例程结束时关闭频道不起作用?@Juanvulcano不,因为那行永远不会执行。@Juanvulcano你在
wg.Wait()之后关闭频道
无论如何。
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()
}