English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Golang 基礎トレーニング

Golang 控制文

Golang ファンクション & メソッド

Golang 枠体

Golang スライス & 配列

Golang 文字列(String)

Golang ポインタ

Golang インターフェース

Golang 並行処理

Golang エラ

Golang 他の雑多

Go 言語のチャネル(Channel)

Go言語では、チャネルはgoroutineが他のgoroutineに通信する媒体であり、その通信はロックフリーです。言い換えれば、チャネルはあるgoroutineがデータを他のgoroutineに送信できる技術です。デフォルトでは、チャネルは双方向です。これは、goroutineが同じチャネルを通じてデータを送信または受信できることを意味します。以下の図を参照してください:

チャネルの作成

Go言語では、chanキーワードを使用してチャネルを作成し、そのチャネルは同じタイプのデータのみを転送することができます。同じチャネルから異なるタイプのデータを転送することは許可されていません。

構文:

var Channel_name chan Type

make()関数を使用してチャネルを宣言する短縮形式を使用することもできます。

構文:

channel_name:= make(chan Type)
package main
import "fmt"
func main() {
    //varキーワードを使用してチャネルを作成します
    var mychannel chan int
    fmt.Println("channelの値: ", mychannel)
    fmt.Printf("channelの型: %T ", mychannel)
    // make()関数を使用してチャネルを作成します
    mychannel1 := make(chan int)
    fmt.Println("\nchannel1の値:", mychannel1)
    fmt.Printf("channel1の型: %T ", mychannel1)
}

出力:

チャネルの値:  <nil>
チャネルの型: chan int
チャネル1の値: 0xc0000160c0
チャネル1の型: chan int

チャネルからデータの送信および受信

Go言語では、チャネルの動作には主に2つの操作があります。一つは送信、もう一つは受信であり、これら2つの操作は通信と総称されます。-演算子の方向はデータの受信または送信を示します。チャネルでは、デフォルトで、送信および受信操作はデータがもう一方にないまでブロックされます。これは、goroutineが明示的なロックや条件変数なしで相互に同期できることを許可します。

  1. 送信操作:送信操作は、チャネルの助けを借りてデータを一つのgoroutineから別のgoroutineに送信するために使用されます。int、floatなど64boolなどの値はコピーされているため、チャネルを通じて安全かつ簡単に送信できます。したがって、同じ値に対する予期せぬ並行アクセスのリスクはありません。同様に、文字列も安全です。なぜなら、それらは変更不可能だからです。しかし、ポインタや参照(例えばスライス、マップセットなど)をチャネルを通じて送信することは安全ではありません。なぜなら、ポインタや参照の値は同時に送信goroutineや受信goroutineによって変更される可能性があり、結果は予測不可能だからです。したがって、チャネルを使用してポインタや参照を使用する場合、一度に一つのgoroutineだけがアクセスできることを確実にする必要があります。

    Mychannel <- element

    上記の文は、データ(element)が<-演算子の助けでチャネル(Mychannel)に送信されます。

  2. 受け取り操作:受け取り操作は、送信側から送信されたデータを受け取るために使用されます。

    element := <-Mychannel

    上記の文は、要素がチャネル(Mychannel)からデータを受け取ることを示しています。受け取った文の結果が利用できない場合(使用しない場合)でも有効な文です。以下のreceive文も書けるです:

    <-Mychannel
package main 
  
import "fmt"
  
func myfunc(ch chan int) { 
  
    fmt.Println(234 + <-ch) 
} 
func main() { 
    fmt.Println("メインメソッドが開始") 
    //チャネルの作成l 
    ch := make(chan int) 
  
    go myfunc(ch) 
    ch <- 23 
    fmt.Println("メインメソッドが終了") 
}

出力:

メインメソッドが開始
257
メインメソッドが終了

チャネルを閉じます

close()関数の助けを借りてチャネルを閉じることもできます。これはビルトイン関数であり、チャネルに値が送信されないことを示す識別子を設定します。

構文:

close()

for範囲ループを使用してチャネルを閉じることもできます。ここでは、受信側goroutineが与えられた構文を使用してチャネルが開いているか閉じているかを確認できます:

ele, ok:= <- Mychannel

ここでは、okの値がtrueの場合、チャネルが開いており、読み取り操作を実行できます。また、okの値がfalseの場合、チャネルが閉じられており、読み取り操作は実行されません。

//Goプログラムの説明
//使用したチャネルを閉じます
//rangeループと閉じる関数
package main
import "fmt"
func myfun(mychnl chan string) {
    for v := 0; v < 4; v++ {
        mychnl <- "w3codebox"
    }
    close(mychnl)
}
func main() {
    //チャネルの作成
    c := make(chan string)
    // Goroutineの使用
    go myfun(c)
    //当okの値がtrueの場合、チャネルが開いており、データの送信や受信ができます
    //当okの値がfalseに設定されている場合、チャネルが閉じられていることを示します
    for {
        res, ok := <-c
        if ok == false {
            fmt.Println("チャネル閉じ", ok)
            break
        }
        fmt.Println("チャネル開放", res, ok)
    }
}

出力:

チャネル開放  w3codebox true
チャネル開放  w3codebox true
チャネル開放  w3codebox true
チャネル開放  w3codebox true
チャネル閉じ false

重要な注意点

  • 送信と受信をブロッキング:チャネルでは、データがチャネルに送信される際に、送信文の制御がブロッキングされ、他のgoroutineがそのチャネルからデータを読み取るまで待機します。同様に、チャネルがgoroutineからデータを受け取るとき、read文のブロッキングが別のgoroutineの送信文まで待機します。

  • ゼロ値チャネル:チャネルのゼロ値はnilです。

  • チャネルのforループ: forループは、閉じられるまでに送信された順序の値を巡回できます。

    構文:

    for item := range Chnl { 
         // 文...
    }
    package main 
    import "fmt"
      
    func main() { 
      
        // make()関数を使用してチャネルを作成します
        mychnl := make(chan string) 
      
        // 匿名goroutine 
        go func() { 
            mychnl <- "GFG"
            mychnl <- "gfg"
            mychnl <- "Geeks"
            mychnl <- "w3codebox"
            close(mychnl) 
        } 
      
        //forループを使用します
        for res := range mychnl { 
            fmt.Println(res) 
        } 
    }

    出力:

    GFG
    gfg
    Geeks
    w3codebox
  • チャネルの長さ:チャネルでは、len()関数チャネルの長さを見つけます。ここでは、長さはチャネルバッファ内に並ぶ値の数を意味します。

    package main 
      
    import "fmt"
    func main() { 
      
        // make()関数を使用してチャネルを作成します 
        mychnl := make(chan string, 4) 
        mychnl <- "GFG"
        mychnl <- "gfg"
        mychnl <- "Geeks"
        mychnl <- "w3codebox"
        // len()関数を使用してチャネルの長さを検索します 
        fmt.Println("チャネルの長さ:", len(mychnl)) 
    }

    出力:

    チャネルの長さ:  4
  • チャネルの容量:チャネルでは、cap()関数を使用してチャネルの容量を見つけることができます。ここでは、容量はバッファのサイズを意味します。

    package main
    import "fmt"
    func main() {
        // make()関数を使用してチャネルを作成します
        mychnl := make(chan string, 4)
        mychnl <- "GFG"
        mychnl <- "gfg"
        mychnl <- "Geeks"
        mychnl <- "w3codebox"
        // cap()関数を使用してチャネルの容量を検索します
        fmt.Println("チャネルの容量:", cap(mychnl))
    }

    出力:

    チャネルの容量:  5
  • チャネルのSelectとcase文:Go言語では、select文は無入力パラメータのswitch文のようなものです。チャネルを使用してselect文からcaseブロックで提供された複数の操作から単一の操作を実行します。