Golangコンカレントモード--channelの高度な使用

17897 ワード

or-done channel


再pipelineの場合、goroutine終了をdoneで通知します.しかしながら、我々が処理したchannelがシステムの他の分散した部分から来た場合、doneによって制御することはできない.なぜなら、データストリームが終了する時間が分からないため、or-doneメカニズムを導入する必要があるからである.or-doneメカニズムは本質的に外部データchannelのパッケージであり、実際に制御することができる.
コードの例を示します.
package main
func main() {
    orDone := func(done, c chan interface{}) chan interface{} {
        valStream := make(chan interface{})
        go func() {
            defer close(valStream)
            for {
                select {
                case done:
                    return
                case v, ok := c:
                    if ok == false {  //  
                        return
                    }
                    select {  //  
                    case valStream  v:
                    case done:
                    }
                }
            }
        }()
        return valStream
    }
}

tee-channel


teeはlinuxのteeコマンドに由来し、このモードの核心的な役割は、送信されたデータストリームをコードの2つの異なる場所に再送信することである.channelを渡し、同じ値を得るために2つの個別のchannelを返します.コードの例を示します.
package main
import "fmt"
func main() {
    tee := func(done chan interface{}, in chan interface{}) (chan interface{}, chan interface{}) {
        out1 := make(chan interface{})
        out2 := make(chan interface{})
        go func() {
            defer close(out1)
            defer close(out2)
            for val := range in {
                var out1, out2 = out1, out2  //  
                for i := 0; i < 2; i++ {
                    select {
                    case done:
                        return
                    case out1  val:
                        out1 = nil  //  select 
                    case out2  val:
                        out2 = nil
                    }
                }
            }
        }()
        return out1, out2
    }
    genetor := func(done chan interface{}, n int) chan interface{} {
        genCh := make(chan interface{})
        go func() {
            defer close(genCh)
            for i := 0; i < n; i++ {
                select {
                case done:
                    return
                case genCh  i:
                }
            }
        }()
        return genCh
    }
    done := make(chan interface{})
    defer close(done)
    out1, out2 := tee(done, genetor(done, 10))
    for val1 := range out1 {
        val2 := out2
        fmt.Printf("%v, %v
"
, val1, val2) } }

ブリッジチャネル


セクタアウトモードでは、入力に秩序は必要ありません.ブリッジchannelはこれとは正反対で,このモードは入力秩序の場合に適用され,複数のデータストリームの入力は秩序ある取得を必要とする.私たちはまず1つのchannelのデータを処理してから、下へ処理を続ける必要があります.このとき、この複数の入力されたchannelを集合としてchannelに単独で配置することができます.
コードの例を示します.
package main

func main() {
    bridge := func(done chan interface{}, chanStream chan chan interface{}) chan interface{} {
        valStream := make(chan interface{})
        go func() {
            defer close(valStream)
            for {
                var stream chan interface{}
                select {
                case maybeStream, ok := chanStream:
                    if ok == false {  //  channel , 
                        return
                    }
                    stream = maybeStream
                case done:
                    return
                }
                // orDone , channel 
                for val := range orDone(done, stream) {
                    select {
                    case valStream  val:
                    case done:
                    }
                }
            }
        }()
        return valStream
    }
}