Pattern for Sequential, Non-Blocking Concurrency

Hello,

I’m working on a project that requires the ability to call a function multiple times in quick succession that will perform a fairly long running operation, be non-blocking and complete in the same call order.

For example, assume a function that counts from 0 to to where to is a given integer parameter and for each number, it will also attempt to calculate the fibonacci sequence concurrently.

func count(to int) {
    for n := 0; n < to; n++ {
        fmt.Printf("Count: %d", n)

        fib(n)
    }
    fmt.Printf("Finished Counting to %d.", to)
}

func fib(n int) {
    // calculate fibonacci sequence to `n`

    fmt.Printf("Fibonacci sequence of %d is %d.", n, answer)
}

The output I’m trying to achieve would be the following where to is 5.

Count: 0
Count: 1
Count: 2
Count: 3
Count: 4
Finished Counting to 5.
Fibonacci sequence of 0 is 0.
Fibonacci sequence of 1 is 1.
Fibonacci sequence of 2 is 1.
Fibonacci sequence of 3 is 2.
Fibonacci sequence of 4 is 3.

My concurrency knowledge with Go isn’t amazing, but my first approach would have been to use a sync.WaitGroup when calculating the Fibonacci sequence. Something like this;

func fib(n int) {
    wg.Add(1)

    go func(n int) {
        // calculate fibonacci sequence to `n`
       wg.Done()
    }(n) 

    wg.Wait()
}

While this does retain the call order, the WaitGroup is redundant as wg.Wait() simply blocks, giving no advantage over calling the function synchronously.

My next approach was to use channels, something similar to the following.

type Counter struct {
    NumbersIn chan int
}

func (counter *Counter) Start() {
    defer close(counter.NumbersIn)

    for number := range counter.NumbersIn {
        fmt.Printf("Count: %d", n)
     
        wg.Add(1)

        go func(n int) {
            fib(n)
            wg.Done()
        }()

        wg.Wait()
    }
}

func (counter *Counter) Count(to int) {
    for n := 0; n < to; n++ {
        counter.NumbersIn <- n
    }

    fmt.Printf("Finished Counting to %d.", to)
}

While this did retain the call order, again like the above attempt it blocks at wg.Wait().

I believe, the solution is some variation of the Pipeline Pattern. But I’m having trouble applying it without getting blocks.

Thanks for any help!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.