同步频道?

时间:2012-01-15 20:56:49

标签: synchronization go channel goroutine

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

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个进程并行。我的想法是将一个频道传递给这些函数供他们写入,但是我怎样才能确保他们能以正确的顺序写入频道?(即正文被写入频道< em>在之后标题和页脚主体之后)

2 个答案:

答案 0 :(得分:5)

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

这是一个最小的例子:

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)
}

答案 1 :(得分:1)

这是一个非常有用的例子供你玩。我在这里有额外的东西来记录序列,这样你就可以看到事情可以按顺序完成,但仍然会尽快显示,但不会早于上一次完成。

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)
}