同步通道?

huangapple go评论81阅读模式
英文:

Synchronized channels?

问题

假设我正在解析某种输入,有以下三个方法:

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

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

i := []byte( /* 输入 */ )
b := new(bytes.Buffer)

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

现在我想通过使用通道来并行执行这3个过程。我的想法是将一个通道传递给这些函数,让它们写入通道,但是__我如何确保它们按照正确的顺序写入通道?__(即确保在头部之后写入主体,在主体之后写入尾部)

英文:

Suppose I'm parsing some kind of input with the following three methods:

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

They all parse a certain part of the same input and return it as []byte, so they can be used like this:

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

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

Now I'd like to make these 3 processes parallel by using channels. My idea was passing a channel to these functions for them to write to, but how can I make sure they will write in the correct order to the channel? (i.e. that the body is written to the channel after the header and the footer after the body)

答案1

得分: 5

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

这是一个最简单的例子:

package main

import "fmt"

func sendme(num int, ch chan int) {
        ch <- num // 将整数 'num' 发送到通道 ch
}

func main() {
        // 创建三个新的通道
        one := make(chan int)
        two := make(chan int)
        three := make(chan int)

        // 以任意顺序作为 go 例程启动每个 "sendme" 的并行调用
        go sendme(3, three)
        go sendme(1, one)
        go sendme(2, two)

        // 按照我们希望处理数据的顺序从每个通道中读取
        fmt.Println(<- one, <- two, <- three)
}
英文:

Essentially you can't, at least not without adding an additional layer of messages to do extra hand-shaking. What would be better to do is to use three separate channels and read from them in the order you want to receive them, that way you don't need to worry about the write-order of the sending processes.

Here's a minimal example:

package main

import &quot;fmt&quot;

func sendme(num int, ch chan int) {
        ch &lt;- num // send integer &#39;num&#39; 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 &quot;sendme&quot; 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(&lt;- one, &lt;- two, &lt;- three)
}

答案2

得分: 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)
}
英文:

Here's a pretty useful example for you to play with. I have extra stuff in here to log the sequences so you can see that things can finish out of order but still display in order, as soon as possible, but no sooner than when the previous finishes.

package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

func deferredString(lbl string, f func() string) (rv chan string) {
	rv = make(chan string)
	go func() {
		s := f()
		fmt.Printf(&quot;Finished %s\n&quot;, lbl)
		rv &lt;- s
	}()
	return rv
}

func do(rv string) string {
	t := rand.Intn(5)
	fmt.Printf(&quot;Sleeping for %d seconds for %s\n&quot;, t, rv)
	time.Sleep(time.Duration(t) * time.Second)
	return rv
}

func main() {
	rand.Seed(int64(time.Now().Nanosecond()))

	cha := deferredString(&quot;a&quot;, func() string { return do(&quot;a&quot;) })
	chb := deferredString(&quot;b&quot;, func() string { return do(&quot;b&quot;) })
	chc := deferredString(&quot;c&quot;, func() string { return do(&quot;c&quot;) })

	fmt.Printf(&quot;a:  %s\n&quot;, &lt;-cha)
	fmt.Printf(&quot;b:  %s\n&quot;, &lt;-chb)
	fmt.Printf(&quot;c:  %s\n&quot;, &lt;-chc)
}

huangapple
  • 本文由 发表于 2012年1月16日 04:56:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/8873320.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定