Go chanネストchanによる関数非同期実行順序戻り値の実現
2883 ワード
問題
非同期はほとんどの開発にとってよく知られていないが,go言語では非同期の実現が異常に便利になった.実行する方法の前にgoキーワードを1つ追加すれば非同期操作を実現できる.しかし、需要がある場合は、呼び出しの前後順(FIFO)で値を返すにはどうすればいいですか.一連のメソッド呼び出しが非同期実行を使用すると、返される前後順序は保証されず、返される前後順序は各関数の消費時間の長さに依存し、消費時間が短い場合は先に返されることが知られています.もちろんこの問題を解決する方法はたくさんありますが、最近読んだ本の中でchanネストchanがこの需要を巧みに実現できることを発見しました.
解決しない前に
まずネストchanを使用していない場合を見てみましょう.コードは簡単で、メソッドoperation 1内部sleep 1秒メソッドoperation 2内部sleep 2秒です.5回の呼び出しはgoroutineで実行され、5つの方法で約2秒かかることがわかります.
結果:実行結果は理想的であるが,5つの方法を実行するのに2秒しかかからなかった.しかし、需要の先進先出(FIFO)のルールに反している.戻り順は完全に関数の時間の長さによって決定されます.
解決方法
ネストされたchanを作成し、chanの値もchanであり、実行時に前後順に追加します.replayでは先進的な先出し順に読み取り、chanブロックで最初の完了を待って次のchanの値を実行します.では、このような実行時間はもっと長くなりますか?答えはあまり影響しません.
結果:実行結果は2秒ですが、結果は異なり、呼び出しの順序で返されます.先進的な先出しの規則に厳格に従う.このように全体的に動作する時間は、実行関数の中で最も時間がかかる関数に依存します.最初の関数が5秒で残りの4つが1秒である場合.main関数全体で5秒かかります
まとめ
実際には、このような問題を解決する方法は一つではありません.例えば、飲み物の返却を要求するときに標識を追加するなどです.しかし,この方法はchanにネストされたchanとgo言語chanのブロック特性を巧みに用いて,この機能コードの簡潔さを実現したと考えられる.性能もあまり消費されず、全体的な実行時間も長くなっていない.また、このネストされた実装は、他の必要な特別なニーズにも使用できる参照方法でもある.
非同期はほとんどの開発にとってよく知られていないが,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のブロック特性を巧みに用いて,この機能コードの簡潔さを実現したと考えられる.性能もあまり消費されず、全体的な実行時間も長くなっていない.また、このネストされた実装は、他の必要な特別なニーズにも使用できる参照方法でもある.