On Wednesday, 22 August 2018 at 16:49:01 UTC, Russel Winder wrote:
Have you tried asyncio in the Python standard library? Is Trio
better?
The library that Guido admits is a disaster?
https://twitter.com/gvanrossum/status/938445451908472832
Trio and libraries like it have evolved out of frustration with
asyncio.
with open_task_container() as container:
container.start_task(a)
container.start_task(b)
await sleep(1)
container.start_task(c)
# end of with block
# program continues (tasks a, b, c must be completed)...
Assuming a, b, and c run in parallel and this is just a nice
Pythonic
way of ensuring join, this is fairly standard fork/join thread
pool
task management
It's far more than "ensuring join". It ensures that tasks
created by children are similarly constrained. It allows the
normal try-catch of exceptions coming from any level of child
tasks. It ensures that when a task has an error, all sibling
tasks are cancelled and the resulting multi-exception is
propagated to the parent.
– except Python is single threaded so the above is time
division multiplexing of tasks.
No, tasks can optionally be real threads (obviously constrained
by GIL). Soon they can be tasks from the "multiprocessing"
library as well (separate process, either local or remote).
These are details of Trio's implementation and Python. As
mentioned, the control structures apply to any concurrency model
(implicit or explicit context switching, OS or light threads,
etc.)
I've not followed async/await in C# but in Python it is a tool
for concurrency but clearly not for parallelism. Sadly
async/await has become a fashion that means it is being forced
into programming languages that really do not need it.
async/await is a means to explicitly mark points of context
switching in API's and code. It applies to threads, coroutines,
remote processing, or anything else which may allow something
else to modify system state while you're waiting.
Local to a single thread, async/await with coroutines happens to
be wonderful because it eliminates a ton of explicit locking,
fretting about race conditions, etc. required of the programmer.
It's a building block-- e.g. you can then combine such threads in
careful ways with message passing within and among CPU cores to
get the best of all worlds.
While Go can certainly implement the nursery and cancellation
control structures, there is no turning back on Go's implicit
context switching (i.e. any old function call can cause a context
switch). The human is back to fretting about locks and race
conditions, and unable to prove that even the smallest of
programs is correct.