亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

與頻道同時寫入

與頻道同時寫入

Go
炎炎設計 2022-01-10 17:14:57
我寫了一個簡短的腳本來同時寫一個文件。一個 goroutine 應該將字符串寫入文件,而其他 goroutine 應該通過通道將消息發送給它。但是,由于某些非常奇怪的原因,創建了文件,但沒有通過通道向其中添加任何消息。package mainimport (    "fmt"    "os"    "sync")var wg sync.WaitGroupvar 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循環它實際上進入文件之后的東西。所以這讓我認為范圍輸出可能為空
查看完整描述

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)

}


查看完整回答
反對 回復 2022-01-10
?
慕碼人2483693

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

}


查看完整回答
反對 回復 2022-01-10
?
蝴蝶刀刀

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


查看完整回答
反對 回復 2022-01-10
  • 3 回答
  • 0 關注
  • 163 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號