Goナレッジポイント(02)-チャネルの不適切な使用によって引き起こされたデッドロック

次のコードを実行した結果はどうなりますか?

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

ですから、私たちはすべてが告白し、各部分が保護され、すべてがエコーの良い習慣を持ち、現在の状態へのタイムリーなフィードバックを持っていることを開発する必要があります

おすすめ

転載: blog.csdn.net/wohu1104/article/details/115336793