Go chanネストchanによる関数非同期実行順序戻り値の実現

2883 ワード

問題
非同期はほとんどの開発にとってよく知られていないが,go言語では非同期の実現が異常に便利になった.実行する方法の前にgoキーワードを1つ追加すれば非同期操作を実現できる.しかし、需要がある場合は、呼び出しの前後順(FIFO)で値を返すにはどうすればいいですか.一連のメソッド呼び出しが非同期実行を使用すると、返される前後順序は保証されず、返される前後順序は各関数の消費時間の長さに依存し、消費時間が短い場合は先に返されることが知られています.もちろんこの問題を解決する方法はたくさんありますが、最近読んだ本の中でchanネストchanがこの需要を巧みに実現できることを発見しました.
解決しない前に
まずネストchanを使用していない場合を見てみましょう.コードは簡単で、メソッドoperation 1内部sleep 1秒メソッドoperation 2内部sleep 2秒です.5回の呼び出しはgoroutineで実行され、5つの方法で約2秒かかることがわかります.
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {

    resultCh := make(chan string)
    //   gotoutine           
    go replay(resultCh)
    //  waitgroup       gorountie    ,    
    wg := sync.WaitGroup{}

    startTime := time.Now()

    //operation1  sleep 1 
    //operation2  sleep 2 
    //              8   
    //              2 
    //                   
    operation2(resultCh, "aaa", &wg)
    operation2(resultCh, "bbb", &wg)
    operation1(resultCh, "ccc", &wg)
    operation1(resultCh, "ddd", &wg)
    operation2(resultCh, "eee", &wg)
    wg.Wait()
    endTime := time.Now()
    fmt.Printf("Process time %s", endTime.Sub(startTime))
}

func replay(resultCh chan string)(){
    for{
        fmt.Println(

結果:実行結果は理想的であるが,5つの方法を実行するのに2秒しかかからなかった.しかし、需要の先進先出(FIFO)のルールに反している.戻り順は完全に関数の時間の長さによって決定されます.
operation1:ddd 
operation1:ccc 
operation2:aaa 
operation2:eee 
operation2:bbb
Process time 2.002555639s

解決方法
ネストされたchanを作成し、chanの値もchanであり、実行時に前後順に追加します.replayでは先進的な先出し順に読み取り、chanブロックで最初の完了を待って次のchanの値を実行します.では、このような実行時間はもっと長くなりますか?答えはあまり影響しません.
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    resultCh := make(chan chan string, 5000)
    wg := sync.WaitGroup{}
    go replay(resultCh)
    startTime := time.Now()
    operation2(resultCh, "aaa", &wg)
    operation2(resultCh, "bbb", &wg)
    operation1(resultCh, "ccc", &wg)
    operation1(resultCh, "ddd", &wg)
    operation2(resultCh, "eee", &wg)
    wg.Wait()
    endTime := time.Now()
    fmt.Printf("Process time %s", endTime.Sub(startTime))
}

func replay(resultCh chan chan string)(){
    for{
        //    chan                              chan 
        c := 

結果:実行結果は2秒ですが、結果は異なり、呼び出しの順序で返されます.先進的な先出しの規則に厳格に従う.このように全体的に動作する時間は、実行関数の中で最も時間がかかる関数に依存します.最初の関数が5秒で残りの4つが1秒である場合.main関数全体で5秒かかります
operation2:aaa
operation2:bbb
operation1:ccc
operation1:ddd
operation2:eee
Process time 2.002714923s

まとめ
実際には、このような問題を解決する方法は一つではありません.例えば、飲み物の返却を要求するときに標識を追加するなどです.しかし,この方法はchanにネストされたchanとgo言語chanのブロック特性を巧みに用いて,この機能コードの簡潔さを実現したと考えられる.性能もあまり消費されず、全体的な実行時間も長くなっていない.また、このネストされた実装は、他の必要な特別なニーズにも使用できる参照方法でもある.