Golang並行プログラミングの実践|GoTheme Month

人間は非常に同時性の高い種であり、繊細です。

最初の知人

Go言語の第一印象は、並行プログラミングをネイティブにサポートし、スレッドよりも軽量なコルーチンを使用していることです。

ybk93cwmg3y51.jpg

プロセス、スレッド、コルーチンの違い

  • プロセスは、システムリソースを割り当てるエンティティとして機能する「プログラム実行のインスタンス」です。プロセスの作成では、完全に別個のアドレス空間を割り当てる必要があります。プロセスの切り替えは、カーネルモードでのみ発生します。
  • スレッド:スレッドは、独自のプログラムコードを独立して実行するプロセスの実行フローであり、プログラム実行フローの最小単位であり、プロセッサのスケジューリングとディスパッチの基本単位です。プロセスは1つ以上のスレッドを持つことができます。
  • コルーチン:コルーチンはプロセスやスレッドではなく、その実行はサブルーチン、または戻り値のない関数呼び出しに似ています。並行コルーチンは言語レベルで作成し、それらを管理するために作成できます。コルーチンを同時に実行するためのコストを削減するために、このステップをアウトソーシングしてください。

a.jpeg

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つのキーワードgogoroutineが、実際には、対処する必要のある問題がまだあります。

元のリンク:k8scat.com/posts/code-…

おすすめ

転載: juejin.im/post/6944362687811813412