>>> The async block as I'm picturing it has nothing to do with function 
>>> colouring, it's about the outermost function in an async stack being able 
>>> to say "make sure the scheduler is started" and "block here until all child 
>>> fibers are either concluded, detached, or cancelled".
>>
>> There's no need for such a construct, as the awaitAll function does 
>> precisely what you describe, without the need to introduce the concept of a 
>> child fiber and the excessive limitation of an async block that severely 
>> limits concurrency.
>
> No, it's not quite that either. The scenario I have in mind is a web / 
> network server spawning a fiber for each request, and wanting to know when 
> everything related to that request is finished, so that it can manage 
> resources.
>
> If we think of memory management as an analogy, awaitAll would be equivalent 
> to keeping track of all your memory pointers, and making sure to pass them 
> all to free before the end of the request. The construct we're discussing is 
> like a garbage collection checkpoint, that ensures all memory allocated 
> within that request has been freed, even if it wasn't tracked anywhere.
>
> Written in ugly functions rather than concise and fail-safe syntax, it's 
> something like:
>
> $managedScope = new ManagedScope;
> $previousScope = set_managed_scope( $managedScope );
>
> spawn handle_request(); // inside here any number of fibers might be spawned
>
> $managedScope->awaitAllChildFibers(); // we don't have the list of fibers 
> here, so we can't use a plain awaitAll
>
> set_managed_scope( $previousScope );
> unset($managedScope);
>
>
> It's certainly worth discussing whether this should be mandatory, default 
> with an easy opt-out, or an equal-footing alternative to go-style unmanaged 
> coroutines. But the idea of automatically cleaning up resources at the end of 
> a task (e.g. an incoming request) is not new, and nor is arranging tasks in a 
> tree structure.


I still strongly disagree with the concept of this construct.

When we spawn an async function, we care only about its result: all side 
effects (including spawned fibers I.e. to handle&cache incoming events from 
sockets, etc..) should not interest us, and eventual cleanup should be handled 
trasparently by the library we are invoking (i.e. very simply by running 
awaitAll in a __destruct, according to the library's overall lifetime and 
logic).

I don't think the language should offer a construct that essentially makes sure 
that an async function or method may not spawn background fibers.

This makes no sense, in a way it's offering a tool to meddle with the internal 
implementation details of any async library, that can prevent libraries from 
using any background fibers.

To make an analogy, it's like saying PHP should have an io {} block, that makes 
sure all file resources opened within (even internally, 10 stack levels deep 
into 3 libraries, whose instances are all used after the io {} block) are 
closed when exiting.

Libraries can and should handle cleanup of running fibers by themselves, on 
their own terms, without externally imposed limitations.

> I would also note that the concept of parent and child fibers is also useful 
> for other proposed features, such as cascading cancellations, and having 
> environment-variable style inherited context data.

Yes, parenting does make sense for some usecases (indeed I already previously 
proposed parenting just for cancellations), just not to offer a footgun that 
explicitly limits concurrency.

Regards,
Daniil Gentili.

Reply via email to