2017-05-03 10 views
-1

多分、マルチスレッド・プログラムを扱っていないPHP開発者がゴーランとチャネルを学び始めるでしょう。golangチャンネルを理解する。すべてのゴルーチンが眠っている - デッドロック[ツアー・オブ・ゴー・クローラー]

私は私が私のクロール方法 、しかしできるだけ簡単なコードを記述しようとしている、囲碁のツアーの最後の練習に[Exercise: Web Crawler](私はこの1つ前に他の演習で問題はなかった)

よ次のようになります。

fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [chan send]: 
main.Crawl(0xf37c1, 0x12, 0x4, 0x1600e0, 0x104401c0, 0x104000f0) 
    /tmp/sandbox452918312/main.go:64 +0x80 
main.main() 
    /tmp/sandbox452918312/main.go:87 +0x60 

func Crawl(url string, depth int, fetcher Fetcher) { 
    // kick off crawling by passing initial Url to a Job queue 
    Queue <- Job{ 
     url, 
     depth, 
    } 

    // make sure we close the Queue channel 
    defer close(Queue) 

    // read from the Queue 
    for job := range Queue { 
     // if fetched or has hit the bottom of depth, 
     // just continue right away to pick up next Job 
     if fetched.Has(job.Url) || job.Depth <= 0 { 
      continue 
     } 
     fres := fetcher.Fetch(job.Url) 
     fetched.Add(job.Url, fres) 
     for i := range fres.Urls { 
      // send new urls just fetched from current url in Job 
      // to the Queue 
      Queue <- Job{ 
       fres.Urls[i], job.Depth - 1, 
      } 
     } 
    } 

    for _, res := range fetched.m { 
     fmt.Println(res) 
    } 
} 

go runは私がどんなgoコードを書くとPHPに戻って得るべきではないと言います

もちろん、私はこの問題を探究しており、結論は通常「あなたの肌を閉じます」と言いました。

私はここで何が欠けているのか誰かが指摘できますか?

完全なコードはここにある:https://play.golang.org/p/-98SdVndD6

この演習のための最も慣用golangの方法は何ですか?私はそれらの少数を見つけた。など

一つはあなたにきれいな解決策になると思われますか?

また、チャネルを使用すると、とゴルーチンが必要ですか?

+2

が、バッファリングされていないチャンネルをデッドロック対応する受信が完了するまでブロックします。ジョブを 'Queue'チャンネルで送信すると、そのオブジェクトを受信するのを待ちます。これは、同じ機能で後で受信しようとするために起こることはありません。チャンネルの詳細については、https://golang.org/doc/effective_go.html#channelsをご覧ください。 –

答えて

1

キューの終了を「延期」しています。これは、「この機能(Crawl)が終了したときにキューを閉じる」を意味します。その後

あなたはそれまでブロックしますループを入力し、次のいずれか

「仕事」がありますがキューに追加閉じているアイテムや

  • 「キュー」を受け取ります最初の実行の最後に、ループは上記の2つの条件のいずれかが再び満たされるまでブロックされます。

    注:最初のループを実行すると、キューにアイテムが追加される可能性があります(繰り返し回数が増える可能性があります)が、ある時点でループのキューが使い果たされ、ループが再び待機します上記の2つの条件のうち、

    しかし、これ以上の項目はキューに追加されないため(#1は失敗する)、この関数が終了した後にのみ 'キュー'が閉じられます。ループが終了するまで#2は失敗します)。

    TLDR:関数が終了するためにあなたのループが待っている、とあなたの関数は、あなたのループが終了するのを待っている -

    私は完全な答えのために、今の時間を持っていない
  • +0

    ありがとうございました!しかし、私はコードが悪いと思う。どのチャンネル**がどのようなもので、どのように動作するかを正確に理解するには、一日かかりました。 「事態が悪い」ということは、コードが最初のループに到達することさえなく、ステートメントを延期することさえできないということです。https://play.golang.org/p/G96SoHdgUBバッファーに入れられていないチャンネルが次のコードでどのようにブロックされているか教えてください。 wrote:https://play.golang.org/p/ZFTSTrMDeAコードを書き直す方法を知りましたが、今日は疲れています。 – Nemoden

    +0

    はい、プレイグラウンドへの2番目のリンクは良いですgoroutineはメモリに永遠に(gc'edされることはありません)、私は物事が変わるとは思わない(おそらく)そのようなぶら下がっているgoroutinesを許容する方法はないからです。https://github.com/golang/go/issues/19702 – Nemoden

    関連する問題