次のコードを実行した結果はどうなりますか?
package main
import (
"fmt"
)
func main() {
c := make(chan string) // 创建一个无缓冲的通道
c <- "hello world"
fmt.Println(<-c)
}
答えは次のとおりです。デッドロックが発生します
fatal error: all goroutines are asleep - deadlock!
理由は次のとおりです。バッファリングされていないチャネルの場合、メッセージを確実に受信できるように、送信者と受信者を同時に準備する必要があります。送信者と受信者の上のコードがあり、main goroutine
両方を同時に実行することはできません。次々に実行する必要があります。これにより、送信者は、障害物のために受信者、送信者、および受信者ができるまで待機します。実行されない最後に、最終的な結果はデッドロックになります。
送信者がチャネルにメッセージを送信するときに、この時点で受信者の準備ができていない場合、送信者は常にブロックされ、受信者が到着するのを待ちます。受信者がそこにいない場合、デッドロックが発生します。
この問題を解決する方法は?
チャネルは一般に異なるコルーチン間の情報交換に適用できることを知っておく必要があります。したがって、上記の問題を解決するために、送信者と受信者を異なるコルーチンにすることができます。
以下のコードを参照してください
func main() {
ch := make(chan string) // 创建一个无缓冲的通道
// 启动一个协程
go func(c chan string) {
c <- "hello world"
}(ch)
fmt.Println(<-ch)
}
出力は次のとおりです。
hello world
ただし、バッファチャネルがある場合、上記のデッドロックの問題は発生しません。
func main() {
c := make(chan string, 1) // 容量为 1 的有缓冲通道
c <- "hello world"
fmt.Println(<-c)
}
結果は実行後に正常に印刷できるため、バッファリングされたチャネルでは、送信者と受信者が同時に準備できている必要はありません。送信者がチャネルにメッセージを送信した後、送信でき、受信者はメッセージのみを必要とします。到着したらチャンネルに入れてください。
しかし、私たちは次のコードを見続けます
func main() {
c := make(chan string, 1) // 容量为 1 的有缓冲通道
c <- "hello"
c <- "world"
fmt.Println(<-c)
}
操作の結果はどうなりますか?
fatal error: all goroutines are asleep - deadlock!
バッファチャネルがある場合、なぜデッドロックが発生するのですか?
その理由は、ここに容量1のバッファチャネルが作成され、コード内で2つのメッセージが連続して送信されるためです。最初のメッセージが送信されると、チャネル内のメッセージの数は容量と等しくなり、この時点で、送信を待つことしかできませんチャネル内のメッセージは、削除された後にのみ送信できます。チャネル内のメッセージが削除されるまで、送信者はブロックされます。
つまり、バッファリングされたチャネルがあります。チャネル情報の数がチャネル容量と等しい場合、送信者は受信者がメッセージを削除するまでブロックを続け、送信者は容量が残っているときに送信を続けます。
したがって、送信が送信され、受信者がメッセージのフェッチを待機している場合、どうなりますか?
func main() {
ch := make(chan string)
go func() {
ch <- "hello"
ch <- "world"
}()
for data := range ch {
fmt.Println(data)
}
}
出力結果:
hello
world
fatal error: all goroutines are asleep - deadlock!
デッドロックが再び発生しました、これはなぜですか?
その理由は、送信者が送信後にそれを無視するためですが、何ですか?受信者は送信者が送信を完了したかどうかを知らないため、永久に待機し、最終的にデッドロックを引き起こします。
それを解決する方法は?
送信者が送信を終えた後、私が送信を終了したことを受信者に伝えるだけです。最後のメッセージを受け取った後、家に帰ることができます。義理の娘と息子があなたが家に帰るのを待っています。
受信者に伝える方法は?close()
チャネル外での使用は非常に簡単です。
func main() {
ch := make(chan string)
go func() {
ch <- "hello"
ch <- "world"
close(ch) // 发送完毕后关闭通道
}()
for data := range ch {
fmt.Println(data)
}
}
ですから、私たちはすべてが告白し、各部分が保護され、すべてがエコーの良い習慣を持ち、現在の状態へのタイムリーなフィードバックを持っていることを開発する必要があります。