Saw this come across my desk and thought it was interesting: https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/
tl;dr explicit fork-join points where if any method inside the block tries to spin up background tasks they are somehow tracked by the block and it won't return until all the forked jobs have returned.
For those you don't want to read the entire article, I'll try to summarize this model of "structured concurrency". I won't try to describe what minimally constitutes structured concurrency, instead I'll try to describe an idealized realization based on fibers.
I'll use the term fiber to describe lightweight "green threads" implemented by the underlying runtime.
So far so good, but for structured concurrency we also want to be able to express program's concurrent structure in similar way as we do for normal structured code, which leads to a parent-child hierarchical organization between fibers.
Again, ideally we'd want the following capabilities:
(Disclaimer: This list ^^^ represents a rough sketch, not a full description of semantics)
These sorts of structuring mechanisms provide safer guarantees (determinism) about how a given program will execute, especially from a resource management standpoint. The goal is to help write program that use minimal resources and don't leak resources along the way.
(This style of parent-child supervision should be familiar to those who have been exposed to the Erlang actor model.)
The point of the article is that while Go has fibers ("goroutines"), it doesn't enforce structured concurrency which leads to either 1) a lot of issues/bugs because the program's structure gets unwieldy, or 2) a lot of ad-hoc (read: unsatisfying) approaches trying to recreate a proper structured concurrency model.
I love this article. Actually thought about it a lot in the context on Nim and how Nim’s any and all async constructs are similar to the ones proposed in the article and how they are different.
I still believe the significance of this article is yet to be acknowledged. Raw threads and async procs are indeed very inconvenient to work with, even if you get used to them enough and convince yourself they’re nice.
Nah, the article is just an ads for the lib which give nothing new, it's just:
var op1 = await myFunc()
var op2 = await anotherFunc() # don't start anotherFunc when myFunc not finished yet
if we "structurize" our operations as synchronous tasks.
or
var ops = await all([myFunc(), anotherFunc()]) # we await both of task to finish
#or
var futops = [myFunc(), anotherFunc()]
# now we do another things before we need the result from futops
var opres = await all futops
# we need the results before we can progress to next
# so we await our previous ran tasks to report the results
# in case of we get error result, whether we cancel altogether next tasks in this scope
# or provide a default value or maybe just propagate the error to next tasks
if we "structurize" our operations as concurrent tasks.
or with Golang's go and its select or with Javascript Promise, or Event emitter, or nowadays it also has Async-Await or with Erlang's receive or with any other languages synchronization's mechanism.
In the end, it's about how we "structurize" our operations within our defined scope. Nothing about sudden jump between tasks' scopes.
i dont think this article is just an ad to particular project, now python's asyncio introduced similar concept: taskGroup, it's a part of structured concurrency; and some other languages also provide simular functionality before or after this article came out.
other parts like cancelScope, which i think is elegant and essential thing for async programming that nim have not had yet.