Вопрос

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)

Это было полезно?

Решение

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

Другие советы

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 (
    "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)
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top