ゴルーチン
通信シーケンスプロセスCSPは、異なるゴルーチン間で値を渡す並行モードですが、変数自体は単一の実行プログラムに制限されています。
同時に実行される各アクティビティはgoroutineと呼ばれます。
プログラムが開始すると、メイン関数を呼び出すgoroutineは1つだけです。これは、メインgourounieと呼ばれます。
新しいgoroutineは、goステートメントによって作成されます。構文的には、通常の関数またはメソッド呼び出しの前にgoキーワードを追加します。
f() //调用f(),等待返回
go f() //新建一个调用f()的goroutine,不用等待
メイン関数が戻り、すべてのゴルーチンが直接終了し、プログラムが終了します。
あるgorounieが別のgorounieを停止する手順はありません。
goroutineと通信して停止を要求する方法があります。
func main(){
listenser, err := net.Listen("tcp", "localhost:8080")
if err != nil{
log.Fatal(err)
}
for{
conn, err := linstenser.Accept()
if err != nil{
log.Println(err) //连接终止
continue
}
go handleConn(conn) //并发处理
}
}
チャネル
Groroutineは同時実行組織であり、チャネルはそれらの間の接続です。
チャネルは、ゴルーチンが特定の値を別のゴルーチンに送信できるようにする通信メカニズムです。
各チャネルは、チャネルの要素タイプと呼ばれる特定のタイプのカテーテルです。
int型要素のチャネルはchan intと記述されます。
初期化
組み込みのmake関数を使用してチャネルを作成します。
ch := make(chan int) //ch的类型是chan int, 无缓冲通过
ch := make(chan int, 0) //无缓冲通道
ch := make (chan int, 3) //容量为3的缓冲通道
チャネルは、makeを使用して作成されたデータ構造への参照です。
関数にパラメーターとしてコピーまたは渡す場合、コピーは参照であり、呼び出し元と呼び出し先の両方が同じデータ構造を参照します。
チャネルのゼロ値はnilです。
同じタイプのチャネルは==シンボル比較を使用でき、2つが同じチャネルデータ参照である場合、値はtrueです。nilと比較することもできます。
チャネルの2つの操作
sendステートメントは、あるゴルーチンから別のゴルーチンに値を送信して、受信したゴルーチンを実行します。
送信(送信):ch <-x //ステートメントを送信
受信:x = <-ch //割り当てステートメントで式を受信
<-ch //ステートメントを受け取り、結果を破棄する
3番目の操作:閉じる(ch)
フラグビットを設定して、現在の送信が完了したことを示します。このチャネルは無意味です。
閉じたパスで操作を受信すると、パスが空になるまで、送信されたすべての値が取得されます。
チャンネルタイプ
バッファなしチャネル:バッファなしのチャネル
パイプライン、パイプライン:シリアルチャネル
単方向チャネル:単方向チャネル
バッファチャネル:バッファ付きチャネル
バッファなしチャネル
バッファリングなしの同期では、送信側のゴルーチンは値を受信した後に再びウェイクアップします。
同時実行性:必ずしも同時に発生するわけではありませんが、発生の順序を決定することはできません。
シリアル:依存関係があり、発生時間の順序は固定されています。
並列:同時に発生する可能性があります。
func main(){
conn, err := net.Dial("tcp", "localhost:8080")
checkError(err)
done := make(chan struct{})
go func(){
io.Copy(os.stdout, conn)
log.Println("done")
done <- struct{}{} //指示主goroutine
}()
mustCopy(conn, os.stdin)
conn.close()
<- done //等待后台goroutine完成
}
パイプライン
カウンター————>正方形————>プリンター
0、1、2、3 ... 0、1、4、9 ...
送信者がデータがないことを知っている場合、ゴルーチンが待機を停止して閉じることを受信者に通知することが効果的です(ちゃん)
チャネルが閉じられた後、後続の送信操作によりアプリケーションがクラッシュします。
閉じたチャネルが読み取られると、後続のすべての受信操作は引き続き実行できますが、取得される値はゼロです。
func main(){
naturals := make(chan int)
squares := make(chan int)
//counter
go func(){
for x := 0; x < 100; x++{
naturals <- x
}
close(naturals)
}()
//square
go func(){
for x := range natruals{
square <- x*x
}
close(square)
}()
//printer 在主goroutine中
for x := range squares{
fmt.println(x)
}
}
単方向チャネル
chan <-int:送信のみ可能です。
<-chan int:受け取ることしかできません。
func counter (out chan <- int){
for x:= 0; i < 100; x++{
out <- x
}
close(out)
}
func squarer (out chan <- int, in <- chan int){
for v := range in{
out <- v:v
}
close(out)
}
func printer (in <- chan int){
for v := range in{
fmt.Println(v)
}
}
//任何赋值操作将双向通道转换为单向通道都允许的,反过来不行
func main(){
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squares(squares, naturals)
printer(squares)
}
バッファチャンネル
容量先入れ先出しキュー。
組立ラインは、チャネルとゴルーチンの適切なメタファーです。
チャネルがいっぱいの場合、チャネルのすべての送信操作は、チャネル内のすべての要素が削除されるまでブロックされます。このとき、チャネルは最も早く待機しているゴルーチンに優先的に通知し、再度送信動作を行います。
チャネルが空の場合、そのチャネルの受信操作は、チャネルに新しい要素が現れるまでブロックされます。このとき、チャネルは優先して最先の待機ゴルーチンに通知し、再度受信動作を行わせます。