Golang のチャンネルは閉鎖されました

PHPz
リリース: 2023-05-12 22:18:36
オリジナル
2108 人が閲覧しました

開発プロセス中、Golang のチャネルを使用する必要がよくあります。チャネルを使用してタスクを完了するときは、プログラムの最適化の効果を得るために、ブロックを避けるために時間内にチャネルを閉じる必要があります。

では、どのような状況でチャンネルを閉じる必要があるのでしょうか?チャンネルを正しく閉じるにはどうすればよいですか? Golang では、チャネルのクローズは確かに比較的複雑なトピックなので、以下でこのトピックを詳しく見てみましょう。

1.なぜチャンネルを閉じる必要があるのですか?

まず、チャネルを閉じる必要がないことを明確にする必要があります。つまり、チャネルへの最後のポインタが破棄されると、Golang は自動的にチャネルを閉じます。ただし、チャネルを閉じないと、次の問題が発生します:

  1. メモリ リーク。閉じられていないチャネルは常にメモリを占有し、データの送受信を待機するため、メモリ リークが発生します。 ######ブロック。閉じられていないチャネルは常にデータの送受信を待機するため、待機時間が長すぎるとプログラムがブロックされる可能性があります。
  2. リソースを時間内に解放できません。一部のシナリオでは、複数のゴルーチンの動作を調整するためにチャネルを使用する必要があります。チャネルが時間内に閉じられないと、リソースが時間内に解放されず、プログラムの実行効率に影響を与える可能性があります。
  3. 2. チャンネルを正しく閉じるにはどうすればよいですか?

チャンネルを閉じる必要がある理由は分かったので、チャンネルを正しく閉じるにはどうすればよいでしょうか?実際、Golang ではチャネルを閉じる 2 つの方法が提供されています。

close() 関数を使用する
  1. チャネルを閉じる最も簡単で一般的な方法は、 golangの()関数によって提供されるclose。この関数の構文形式は次のとおりです:
close(channel)
ログイン後にコピー

この関数はチャネル タイプ パラメータを渡す必要があります。渡されたチャネル タイプ パラメータがクローズされている場合、再度送受信することはできません。そうでない場合はパニックが発生します。 。

for range ループを使用してチャネルを閉じる
  1. チャネルを閉じる 2 番目によく使用される方法は、for range ループを使用することです。この方法は受信に役立ちます。チャネルからの値。比較的一般的です。チャネルにデータを送信する操作の場合、このメソッドがチャネルを閉じるために使用されることはほとんどありません。 for range ループを使用してチャネルを閉じるコード例は次のとおりです。
for val := range channel {
    fmt.Println(val)
}

// channel被关闭后,上述代码会正常退出循环
ログイン後にコピー

for range ループでは、チャネルが閉じられると、ループは自動的に終了します。 for range ループ内で Break や continue などのステートメントを使用してループから抜け出すと、チャネルの受信操作が継続されることを避けることができないことに注意してください。

3. チャネルの閉鎖によるパニックを回避するにはどうすればよいですか?

close() 関数を使用してチャネルを閉じる場合、注意すべき重要な点の 1 つは、チャネルにすべての値を送信するすべての操作が完了した後にチャネルが閉じられていることを確認する必要があることです。シャットダウン操作を実行すると、パニックが発生する可能性があります。このようなことが起こらないようにする方法を見てみましょう。

キャッシュされたチャネルの使用
  1. データを送信する前に実行する必要がある複雑な計算や検証操作の場合、キャッシュされたチャネルを使用してパニック状況を回避できます。具体的な実装は次のとおりです。
ch := make(chan bool, 1)
go func() {
    // 进行复杂计算或者校验操作
    // ...
    ch <- true
}()

select {
case <- done:
    // 结束操作
case <- ch:
    // 处理收到的数据
}
close(ch)
ログイン後にコピー

上記のコードでは、バッファー 1 のチャネルを使用します。このチャネルにはブール値のみが格納されます。ゴルーチンの作成後に複雑な操作が完了すると、操作が完了したことを示す true 値をチャネルに送信します。次に、select ステートメントでチャネルに値を送信するか、他のチャネルから値を受信するのを待ちます。最後に、close() 関数を使用してチャネルを閉じます。

select ステートメントの使用
  1. select ステートメントを使用すると、チャネルが閉じる前にデフォルトのブランチを使用してシナリオを処理できます。コード例は次のとおりです。
func handleCh(channel chan int) {
    for {
        select {
        case val, ok := <- channel:
            if !ok {
                fmt.Println("channel has closed")
                return
            }
            fmt.Println("recieve val:", val)
        default:
            fmt.Println("no value received")
        }
    }
}

func main() {
    ch := make(chan int)
    for i := 0; i < 5; i++ {
        go func(val int) {
            ch <- val
        }(i)
    }
    close(ch)
    handleCh(ch)
}

// 输出结果:
// recieve val: 0
// recieve val: 1
// recieve val: 2
// recieve val: 3
// recieve val: 4
// channel has closed
ログイン後にコピー

上記のコードでは、チャネルから受信した値を処理する handleCh() 関数を作成しました。この関数では、select ステートメントを使用してチャネルから受信したデータを処理し、デフォルト ブランチでチャネルが閉じられていない場合のシナリオを処理します。 main関数でチャネルを閉じると、handleCh()関数は正常に終了します。ただし、デフォルトのブランチを使用する場合は、それを最後に配置する必要があることに注意してください。そうしないと、プログラム エラーが発生します。

4. 概要

上記の紹介を通じて、Golang でチャネルを閉じる理由と方法を理解しました。一般に、メモリ リークやブロッキングなどの問題を回避するには、チャネルを手動で閉じる必要があります。チャネルを閉じるときは、パニックを避けるために close() 関数または for range ループ ステートメントをそれぞれ使用する必要があります。現在、実際の開発では、キャッシュされたチャネルまたは select ステートメントを使用して、チャネルが閉じる前にシーンを処理し、プログラムの効果を最適化するという目的を達成できます。

以上がGolang のチャンネルは閉鎖されましたの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート