How to Write Concurrent Go Code
… continued from the previous post.
Shuffling through Stack Overflow questions I realized that there is one point I tried to make clear, but didn’t emphasize enough:
Write Synchronous Code First #
Many programs work perfectly fine without concurrency. It’s better to prioritize creating a functional and thoroughly tested program initially and introduce concurrency when its benefits become apparent through observation of runtime behavior. Rushing into concurrent implementations riddled with bugs invariably results in more time spent on subsequent fixes of a bad design and less on real improvement; moreover, it’s more efficient to start with a straightforward approach and iterate towards improvement, rather than to deal with a buggy program and invest significant time in bug fixes afterward.
Problems in the Wild #
Let me give some examples. It’s so much better to have:
|
|
And realize - well, you can’t make it concurrent, because one function depends on the result of the other, and besides - it is fast enough - instead of being stuck with Frankenstein’s monster:
|
|
which is slower than the first example.
And it is also so much easier instead of guessing what should be concurrent up front to start with synchronous code:
|
|
and should you find out that executing sub1
and sub2
concurrently could speeds thing up, transform it to:
|
|
What makes things much better here is that sub1
and sub2
still have unchanged, synchronous APIs, which means that
all tests you’ve written are still valid and things are much easier to test, since you don’t have to deal with
concurrency.
The transformation only happens in task
, and at that scope concurrency is better to understand.
Be Considerate #
I do not believe everything should be written using structured concurrency. But seeing common Go bugs, I think that a lot of code written would benefit.
Summary #
Most of the code should be written synchronously first and should keep synchronous APIs as much as possible. Function literals are a great way to separate concurrency from subtasks.
… to be continued.