How Go runtime makes concurrent code simple
5 years ago I showed a way to fight with "all-threads-busy" problem while writing Hopac code. The same problem exists on JVM as well. The root is in the cooperative concurrency model, which is based on thread pools, async/futures/etc. are scheduled to run on them. So, if an async is blocked by an IO call of if it's just executing some computation, the OS thread is not able to do anything else: the scheduler is unable to "pause" such a blocked async and execute anothe one. So, asynchronous code on .NET, JVM, Rust, etc. is inherently unsafe: it's not guaranteed that all existing asyncs progress.
The things are different in Go runtime: the scheduler is preemptive, so it can "pause" goroutines at any point: not only at function calls, at loops, but on just any execution point (almost). This makes writing concurrent code dead easy: there's no "async" functions, lambdas or blocks of code, every function or call are the same, being them executed in "main" thead or in a goroutine.
Let's look at the mention above code being written in Go:
No let!, await, async, do!, StartAsTask, match! and so on. Need to run some code concurrently? Add go keyword. Done.
Comments
> So, if an async is blocked by an IO call of if it's just executing some computation, the OS thread is not able to do anything else: the scheduler is unable to "pause" such a blocked async and execute another one.
I believe there is a simple yet elegant solution for Scala's futures from stdlib: blocking { ... } section. You just wrap a long sync IO in blocking and ExecutionContext will not spend it's computation threads on it. Or you can use a separate ExecutionContext for IO futures if you want more control.
А в Гоу по сути вытесняющая многозадачность, т.е. шедулер может прервать выполнение гоурутины не только на вводе-выводе, но даже в плотном цикле вычислений. В итоге мы имеем все лучшее от мира системных тредов и кооперативной многозадачности (асинки в дотнете, скале и так далее): легковесные гоурутины с поведением тредов. Это настолько шикарно, что надо самому пробовать. Никаких асинков, никого мэппинга, флэтмэппинга, на дай бог блокировки в асинке, сложная обработка ошибок, деление функций на обычные и асинхронные и так далее.