【问题标题】:Synchronized channels?同步频道?
【发布时间】:2012-02-10 23:59:00
【问题描述】:

假设我正在使用以下三种方法解析某种输入:

func parseHeader ([]byte) []byte
func parseBody   ([]byte) []byte
func parseFooter ([]byte) []byte

它们都解析相同输入的某个部分并将其返回为[]byte,因此它们可以这样使用:

i := []byte( /* the input */ )
b := new(bytes.Buffer)

b.Write(parseHeader(i))
b.Write(parseBody(i))
b.Write(parseFooter(i))

现在我想通过使用通道使这 3 个进程并行。我的想法是将通道传递给这些函数以供它们写入,但是 我如何确保它们会以正确的顺序写入通道?(即正文被写入通道 在页眉和页脚正文之后)

【问题讨论】:

    标签: synchronization go channel goroutine


    【解决方案1】:

    基本上你不能,至少在不添加额外的消息层来做额外的握手的情况下是不能的。更好的做法是使用三个单独的通道并按照您希望接收它们的顺序从它们中读取,这样您就不必担心发送进程的写入顺序。

    这是一个最小的例子:

    package main
    
    import "fmt"
    
    func sendme(num int, ch chan int) {
            ch <- num // send integer 'num' down chan ch
    }
    
    func main() {
            // Create three new channels
            one := make(chan int)
            two := make(chan int)
            three := make(chan int)
    
            // Start each parallel invocation of "sendme" as a go routine, in any order
            go sendme(3, three)
            go sendme(1, one)
            go sendme(2, two)
    
            // Read from each channel in the order we wish to process the
            // data
            fmt.Println(<- one, <- two, <- three)
    }
    

    【讨论】:

    • 您能否提供一个示例,说明我如何使用 3 个通道来做到这一点? =) 那太棒了。
    • 好的,完成。显然,您可以稍微整理一下。例如,您可能希望将通道存储在数组中。
    【解决方案2】:

    这是一个非常有用的示例供您使用。我在这里有额外的东西来记录序列,所以你可以看到事情可能会乱序完成,但仍会尽快按顺序显示,但不会早于前一个完成的时间。

    package main
    
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    func deferredString(lbl string, f func() string) (rv chan string) {
        rv = make(chan string)
        go func() {
            s := f()
            fmt.Printf("Finished %s\n", lbl)
            rv <- s
        }()
        return rv
    }
    
    func do(rv string) string {
        t := rand.Intn(5)
        fmt.Printf("Sleeping for %d seconds for %s\n", t, rv)
        time.Sleep(time.Duration(t) * time.Second)
        return rv
    }
    
    func main() {
        rand.Seed(int64(time.Now().Nanosecond()))
    
        cha := deferredString("a", func() string { return do("a") })
        chb := deferredString("b", func() string { return do("b") })
        chc := deferredString("c", func() string { return do("c") })
    
        fmt.Printf("a:  %s\n", <-cha)
        fmt.Printf("b:  %s\n", <-chb)
        fmt.Printf("c:  %s\n", <-chc)
    }
    

    【讨论】:

    • 哇太棒了!非常感谢您。我将对此进行更深入的分析。
    猜你喜欢
    • 2012-10-02
    • 2017-10-20
    • 1970-01-01
    • 2017-11-21
    • 1970-01-01
    • 2018-02-18
    • 2020-04-25
    • 2018-03-04
    • 2020-11-05
    相关资源
    最近更新 更多