snivilised / lorax

🌟 reactive extensions for go (a pseudo rxgo version 3)
MIT License
4 stars 0 forks source link

consider using orDone channel pattern #262

Open plastikfan opened 3 months ago

plastikfan commented 3 months ago

found on youtube learn the Go concurrency pattern that blew my mind (by Kantan Coding) (Not sure if this is applicable to anything in lorax, I just wanted somewhere to record the act that I saw this useful concurrency design pattern)

Allows the done/select channel pattern to be extracted out into another function that handles done notification using a separate go routine and a relay stream. Clients now do not need to implement the select/done channel, they instead range over the relay stream that is returned from the newly defined function orDone.

Here is the example code:

func main() {
    var wg sync.WaitGroup

    cows := make(chan interface{}, 10)
    done := make(chan interface{}, 10)

    wg.Add(1)
    go consumeCows(&wg, done, cows)
}

func consumeCows(wg *sync.WaitGroup, done, cows <-chan interface{}) {
    defer wg.Done()

    for cow := range orDone(done, cows) {
        fmt.Printf("%v\n", cow)
    }
}

func orDone(done, c <-chan interface{}) <-chan interface{} {
    relayCh := make(chan interface{})

    go func() {
        defer close(relayCh)

        for {
            select {
            case <-done:
                return
            case v, ok := <-c:
                if !ok {
                    return
                }
                select {
                case relayCh <- v:
                case <-done:
                    return
                }
            }
        }
    }()

    return relayCh
}

Also see: Go Concurrency Patterns: Pipelines and cancellation by Sameer Ajmani (13-mar-2014)