WIP: feat(coroutines): ability to use coroutines in Symofny#566
WIP: feat(coroutines): ability to use coroutines in Symofny#566Rastusik wants to merge 1 commit into
Conversation
|
Hi, as I don't really have time for this project (as you can see I'm not developing anything new). I can merge it once it passes CI fully so I can release it afterwards. The only requirements are the CI green, and that changes are backward compatible. |
| $this->coWrapper->defer(); | ||
| $httpFoundationRequest = $this->requestFactory->make($request); | ||
| $this->processorInjector->injectProcessor($httpFoundationRequest, $response); | ||
| $kernel = $this->getKernel(); |
There was a problem hiding this comment.
Rename "$kernel" which has the same name as the field declared at line 21.
| private static function getInstance(): self | ||
| { | ||
| if (null === self::$instance) { | ||
| throw new RuntimeException('CoWrapper was not initialised.'); |
There was a problem hiding this comment.
Define and throw a dedicated exception instead of using a generic one.
| /** | ||
| * Generator for proxies with service pool. | ||
| */ | ||
| class AccessInterceptorServicePoolGenerator implements ProxyGeneratorInterface |
There was a problem hiding this comment.
The class AccessInterceptorServicePoolGenerator has a coupling between objects value of 14. Consider to reduce the number of dependencies under 13.
| /** | ||
| * Utility to service pool method interceptor. | ||
| */ | ||
| class InterceptorGenerator |
There was a problem hiding this comment.
Possible parse error: class missing opening or closing brace
| /** | ||
| * Utility to service pool method interceptor. | ||
| */ | ||
| class InterceptorGenerator |
There was a problem hiding this comment.
Possible parse error: class missing opening or closing brace
|
Code Climate has analyzed commit 929969a and detected 13 issues on this pull request. Here's the issue category breakdown:
The test coverage on the diff in this pull request is 0.0% (50% is the threshold). This pull request will bring the total coverage in the repository to 16.8% (-69.2% change). View more on Code Climate. |
Codecov Report
@@ Coverage Diff @@
## develop #566 +/- ##
==============================================
- Coverage 86.03% 15.77% -70.27%
- Complexity 654 737 +83
==============================================
Files 96 115 +19
Lines 2070 2364 +294
==============================================
- Hits 1781 373 -1408
- Misses 289 1991 +1702
|
|
great, I'll look into it! :) |
1d0a531 to
92daab6
Compare
a3f7b7d to
f04782e
Compare
|
@k911 the checks need to be approved to run? I'm not sure which checks you'd like me to fix, if they can't run :) |
Hi @k911 ! :)
This PR is an POC WIP implementation of #561 . Would you please take a look at? What do you think?
TLDR: I was able to use Swoole coroutine hooks (https://www.swoole.co.uk/docs/modules/swoole-runtime-flags) in Symfony, which effectively means, that it is now possible to concurrently execute multiple requests in a Symfony application. The base idea is described in the issue.
Basically what is being done is, that the Symfony container is overridden to create multiple instances of stateful services (which would be a problem for concurrent request processing, if there would be only one instance of them - race conditions would occur). These multiple instances behave as on instance from the POV of the SF container and the app, because they are all hidden behind one service instance (a proxy, which forwards method calls to the right service instance according the current coroutine identifier/context)
When the coroutine hooks are enabled, one request processing will wait on each IO operation, which will make way for a different request to be able to be processed. This way, each IO call is effectively changed to an async/await call in the background of the runtime. It's also possible to use Doctrine with this, the code should be platform independent and now it is possible to use Doctrine in concurrent code.
As a bonus, it is also possible to use the Swoole coroutines, but not by calling
Co::go(...), but by callingCoWrapper::go(...), which wraps the original Swoole function and runs some garbage collection after the coroutine is finished.There still are some quirks to be figured out, e.g. the app kernel has to override the
__clone()method ofSymfony\Component\HttpKernel\Kernel, because Kernel is a stateful service as well... But it works good for now. The other quirk is that this code doesn't run with final stateful services, but this problem is solvable as well.It is also interesting to observe some benchmarks. I got these numbers using
debug:off, WORKER_COUNT:1 REACTOR_COUNT:1(env:coop_schedulingwith Sqlite database with coroutines turned on (I used APCu as cache backend, not php arrays, as committed):And with coroutines turned off:
That's just a slight increase. Not sure how the Sqlite driver works but it seems that it is doing quite a lot in memory, so there is less IO and worse results.
But when testing with MySql as a backend, the results are much more interesting for one web worker process with coroutines:
With coroutines disabled, one web worker process was able to handle only half of the requests:
This should be just the first step, I would like to make something similar for the Swoole task workers.
@k911 what would you say? Will this be possible to merge? Feel free to suggest any changes or improvements.