go言語同時メカニズムgoroutineプローブ

1663 ワード

go言語の大きな利点は、コンカレントプログラムを簡単に作成できることです.go言語にはgoroutineメカニズムが組み込まれています.これはcoroutaine(協程)のようなものです.しかし、全く同じではありません.
例えば、この例では、
package main import (     "fmt";     "strconv" ) func main() {     ch := make(chan int)     task("A", ch)     task("B", ch)     fmt.Printf("begin
") <-ch <-ch } func task(name string, ch chan int) { go func() { i:= 1 for { fmt.Printf("%s %d
", name, i) i++ } ch <- 1 }(); }

実行後、A Bの2つのgoroutineが交互に実行され、従来のコラボレーションのように手動でscheduleする必要があることがわかりました.不思議に見えます.
コードを少し変更して、
fmt.Printf("%s %d
", name, i)

に改心
print(name + " " + strconv.Itoa(i) + "
")

もう一度見てみましょう.不思議な効果が消え、Aだけが動いた.
ではfmt.Printfとprintの違いは何ですか?
大体goのコードをめくってみると、go言語はc libの包装にcgoの方法を使っていることがわかります.cgoでcライブラリを呼び出すと、呼び出し時に自動的にscheduleが切り替えられ、呼び出しが終了したときに返されます.この2つの結果の違いはfmt.Printfはcgoで包装され,printは原生で実現される.だからfmtを呼び出している.Printfの場合、自動的にスケジューリングが実現されます.
従来のcoroutaineは、ネットワーク、データベースなどのio操作にアクセスする際にブロックされ、同時性を失うため、通常、非同期ioと組み合わせて実現する必要があります.既存のライブラリ自体が非同期機能を提供していないと困り、再実現が必要になることが多い.また,非同期io機能があっても,表現上従来のシーケンスプログラムと同様の方法で追加の開発が必要である.
go言語のこのような実現方式はこの問題をよく解決し,既存の大量のcライブラリを十分に利用して包装することができる.
またruntimeも使用できる.Gosched()を使用して手動でスケジュールします.演算量の大きいシーンでも必要です.
printを使用する例ではruntimeを使用するとGOMAXPROCS(2)は、再並列化も可能です.このとき,2つのgoroutineは2つの独立したスレッドで実行される.これはまたgoroutineと協程の違いです.ただし、複数のスレッドを有効にすると、プログラムがより速くなるとは限りません.スレッド間のコンテキスト切り替えのコストも大きいからです.上の簡単な例では、プログラムをもっと遅くします.コンテキスト切替のオーバーヘッドを低減することも、コラボレーションの利点です.