> Let me summarize the current state for today:
> 
> I am abandoning startScheduler and the idea of preserving backward 
> compatibility with await_all or anything else in that category. The scheduler 
> will be initialized implicitly, and this does not concern user-land. 
> Consequently, the spawn function() code will work everywhere and always.
> 

Very glad to hear this, this is the correct approach for concurrency, one that 
will not break all existing libraries and give them the freedom to handle their 
own resource cleanup.

I’ve also seen your latest email about kotlin-like contexts, and they also make 
more sense than an await_all block (which can only cause deadlocks): note how a 
kotlin coroutine context may only be cancelled (cancelling all inner coroutines 
with CancelledExceptions), never awaited.

> 
> >
> >  I can give you several examples where such logic is used in Amphp 
> > libraries, and it will break if they are invoked within an async block.
> >
> 
> Got it, it looks like I misunderstood the post due to my focus. So, 
> essentially, you're talking not so much about wait_all itself, but rather 
> about the parent-child vs. free model.
> 
> This question is what concerns me the most right now.
> 
> If you have real examples of how this can cause problems, I would really 
> appreciate it if you could share them. Code is the best criterion of truth.
> 

Sure:

- https://github.com/amphp/websocket/blob/2.x/src/PeriodicHeartbeatQueue.php
- https://github.com/amphp/redis/blob/2.x/src/Sync/RedisMutex.php

This is the main example where it is most evident that background fibers are 
needed: logic which requires periodic background pings to be sent in order to 
keep a connection alive, a mutex held or something similar. 

Constructing a PeriodicHeartbeatQueueinside of a wait_all block invoking a a 
someClass::connect(), storing it in a property and destroying it outside of it 
in someClass::close or someClass::__destruct, would cause a deadlock (the 
EventLoop::repeat doesn’t technically spawn a fiber immediately, it spawns one 
every $interval, but it behaves as though a single background fiber is spawned 
with a sleep($interval), so essentially it’s a standalone thread of execution, 
collected only on __destruct).

https://github.com/danog/MadelineProto/tree/v8/src/Loop/Connection contains 
multiple examples of tasks of the same kind in my own library (ping loops to 
keep connections alive, read loops to handle updates (which contain vital 
information needed to keep the client running correctly) in the background, 
etc...), all started on __construct when initialising the library, and stopped 
in __destruct when they are not needed anymore.

A coroutine context/scope a-la kotlin is fine, but it should absolutely not 
have anything to await all coroutines in the scope, or else it can cause 
deadlocks with the very common logic listed above.

Regards,
Daniil Gentili.

Reply via email to