2016-05-19 33 views
1

ファイルを同時に書き込むための短いスクリプトを書きました。 1つのgoroutineは文字列をファイルに書き込むのに対し、他の人はチャネルを介してメッセージを送信することになっています。 しかし、いくつかの本当に奇妙な理由のために、ファイルが作成されますが、チャンネルを通じてメッセージが追加されません。Golang:チャネルと同時書き込み

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ループの後に何かを書き込もうとすると完全に実行されます。これは、範囲出力がnullになる可能性があると私に導きます。

+0

あなたはコード例を修正することはできますか?書かれているように、それは動かないだろう。 – Snowman

+0

@スノーマン確かに!私はちょっと時間を与えて、タイプ変数を変更します – Juanvulcano

+1

@Snowman今のはるかに良くなっているはずです、https://play.golang.org/p/Cx6mcUHiSU – Juanvulcano

答えて

1

一つの受信/送信します。

あなたのフローによれば、送信側チャネルは受信側がデータを引き出すことを期待しているため、以下のコードスニペットは決してwg.Done()に届きません。これは典型的なデッドロックの例です。

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

のメインFUNCを調べてみましょう:

func main() { 
    wg.Add(2) 
    go concurrent(1) 
    go concurrent(2) 
    wg.Wait()  // the main thread will be waiting indefinitely here. 
    close(output) 
    printOutput() 
} 

+0

仕事の最後にチャンネルを閉じても問題ありませんか? – Juanvulcano

+0

@Juanvulcanoいいえ、その行は決して実行されません。 – Roylee

+0

@Juanvulcanoあなたは 'wg.Wait()'の後にチャンネルを閉じます。 'output < - fmt.Sprint(n)'は 'printOutput()'が値を取るのを待つので、 'wg.Done()'に達しません。また、 'wg.Wait()'の後にもあるので、printOutput()にアクセスすることはありません。したがって、あなたは 'wg.Done()'を永久に待ちます。 – Snowman

1

出力チャネルから何かを取り除く必要があります。

私はprintOutput()を他の機能の上に移動し、実行ルーチンとして実行し、デッドロックを防止します。あなたはチャンネルは両方のためのblockingであるため、ヌルoutputがあり得る理由の

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) 
} 
関連する問題