Search code examples
gogoroutine

Use of goroutines when steps are sequential


I feel like the answer to my question is no but asking for certainty as I've only started playing around with Go for a few days. Should we encapsulate IO bound tasks (like http requests) into goroutines even if it was to be used in a sequential use case?

Here's my naive example. Say I have a method that makes 3 http requests but need to be executed sequentially. Is there any benefit in creating the invoke methods as goroutines? I understand the example below would actually take a performance hit.

func myMethod() {
   chan1 := make(chan int)
   chan2 := make(chan int)
   chan3 := make(chan int)

   go invoke1(chan1)

   res1 := <-chan1
   invoke2(res1, chan2)

   res2 := <-chan2
   invoke3(res2, chan3)

   // Do something with <-chan3
}

One possible reason that comes to mind is to future proof the invoke methods for when they're called in a concurrent context later on when other develops start re-using the method. Any other reasons?


Solution

  • There's nothing standard that would say yes or no to this question.

    Although you can do it correctly this way, it is much simpler to stick to plain sequential execution.

    Three reasons come to mind:

    • this is still sequential: you're waiting for every single goroutine sequentially, so this buys you nothing. Performance probably doesn't change much if it's only doing an http request, both cases will spend most of their time waiting for the response.
    • error handling is much simpler if you just get result, err := invoke; if err != nil .... rather than having to pass both results and errors through channels
    • over-generalization is a more apt word than "future proofing". If you need to call your invoke methods asynchronously in the future, then change your code in the future. It will be just as easy then to add asynchronous wrappers around your functions.