人間は非常に同時性の高い種であり、繊細です。
最初の知人
Go言語の第一印象は、並行プログラミングをネイティブにサポートし、スレッドよりも軽量なコルーチンを使用していることです。
プロセス、スレッド、コルーチンの違い
- プロセスは、システムリソースを割り当てるエンティティとして機能する「プログラム実行のインスタンス」です。プロセスの作成では、完全に別個のアドレス空間を割り当てる必要があります。プロセスの切り替えは、カーネルモードでのみ発生します。
- スレッド:スレッドは、独自のプログラムコードを独立して実行するプロセスの実行フローであり、プログラム実行フローの最小単位であり、プロセッサのスケジューリングとディスパッチの基本単位です。プロセスは1つ以上のスレッドを持つことができます。
- コルーチン:コルーチンはプロセスやスレッドではなく、その実行はサブルーチン、または戻り値のない関数呼び出しに似ています。並行コルーチンは言語レベルで作成し、それらを管理するために作成できます。コルーチンを同時に実行するためのコストを削減するために、このステップをアウトソーシングしてください。
Goは最も単純な同時実行性を実装します
for i := 0; i < 10; i++ {
go func(n int) {
fmt.Println(n)
}(i)
}
复制代码
プロジェクトの実践
最近、プロジェクトは複数のジョブを同時に呼び出し、これらのジョブが完了するのを待ってから実行する必要があります。
ジョブを連続して実行する
最初に、ジョブを実行し、すべてのジョブを順番に実行するメソッドがあります。
func buildJob(name string) {
...
}
buildJob("A")
buildJob("B")
buildJob("C")
复制代码
ジョブを並行して実行する
すべてのジョブを同時に実行できるため、他のジョブの実行を続行する前に、前のジョブの実行が完了するのを待つ必要はありません。Goキーワードgo
を使用して、 1つをすばやく有効goroutine
にすることができます。以下では、3つのジョブを同時に実行します。
go buildJob("A")
go buildJob("B")
go buildJob("C")
复制代码
すべてのジョブが終了するのを待ちます
各ジョブが完了したかどうかを知る方法。ここではchannel
、通信に使用しselect
たり、実行結果を確認したりできます。
func buildJob(ch chan error, name string) {
var err error
... // build job
ch <- err // finnaly, send the result into channel
}
func build() error {
jobCount := 3
errCh := make(err chan error, jobCount)
defer close(errCh) // 关闭 channel
go buildJob(errCh, "A")
go buildJob(errCh, "B")
go buildJob(errCh, "C")
for {
select {
case err := <-ch:
if err != nil {
return err
}
}
jobCount--
if jobCount <= 0 {
break
}
}
return nil
}
复制代码
問題が見つかりました
ジョブAが失敗すると、build
メソッドreturn err
は終了して実行されclose(errCh)
ます。ただし、この時点では、他の2つのジョブBとCはまだ実行されていない可能性があり、結果は同時に送信されますがerrCh
、この時点で閉じられerrCh
て、プログラムは終了しpanic: send on closed channel
ます。
コードを最適化する
チャネルにデータを送信するとき、受信したデータの2番目の値を使用して、チャネルが閉じているかどうかを判断できます。
func buildJob(ch chan error, name string) {
var err error
... // build job
if _, ok := <-ch; !ok {
return
}
ch <- err // finnaly, send the result into channel
}
func build() error {
jobCount := 3
errCh := make(err chan error, jobCount)
defer close(errCh) // 关闭 channel
go buildJob(errCh, "A")
go buildJob(errCh, "B")
go buildJob(errCh, "C")
for {
select {
case err := <-ch:
if err != nil {
return err
}
}
jobCount--
if jobCount <= 0 {
break
}
}
return nil
}
复制代码
要約する
Go並行プログラミングでは、1つのキーワードgo
をgoroutine
が、実際には、対処する必要のある問題がまだあります。
元のリンク:k8scat.com/posts/code-…