STATE OF ASYNC PHP
Saad Bin Amjad
Technical Lead, Monstarlab Bangladesh
Agenda
1. Problem Statement
2. Asynchronous Concepts
3. Asynchronous Programming
4. Evolution of PHP
5. PHP State of Affairs
6. PHP Async Libraries and Frameworks
7. Laravel Octane
8. Follow up
Problem Statement
More people are online...
More than 5 billions of people now use the internet as of 2021.
Web applications need to be shipped out fast and efficiently that ensures best user experience.
Developer experience is top priority.
Utilising the advance of self hosted or cloud hardware capabilities.
Application Performance
Client side and server side
Client side need to load fast and be responsive.
Server side must be available and return quick responses, handle many requests at the same time, utilize hardware etc.
25+ years of PHP
Full Details are here: https://www.jetbrains.com/lp/php-25/
Do you need asynchronous PHP?
No
Michelin Stars
"exceptional cuisine that is worth a special journey"
"excellent cooking that is worth a detour"
"a very good restaurant"
"Michelin Stars" for Async PHP?
exceptional "pattern" that is worth a special journey
excellent "pattern" that is worth a detour
a very good "pattern"
Asynchronous Concepts
Links
The resources used, inspired from, and great reads for further reading will be pasted here at the bottom
Ramsey in 10
Task: Fish and Chips in 10 mins.
Ramsey in 10
Task: Fish and Chips in 10 mins.
One step at a time
1 Chef, 3 items to make, 1 pan + 1 oven available = 17 mins
Let's us all do this together
3 Chef, 9 items to make, 3 pan + 3 oven available = 17 mins
One might argue 17 / 3 = 6 mins for one.
Need to figure out when I am sitting idle?
Tasks
Tasks when I am free
Gordon Ramsey's way
1 Chef, 3 items to make, 1 pan + 1 oven available = 10 mins
Link:
https://www.youtube.com/watch?v=HrNLvCO2tE4
If we were all Gordon Ramsey
3 Chef, 9 items to make, 3 pan + 3 oven available = 10 mins
One might argue 10 / 3 = 3 mins for one.
So what we learn from Gordon Ramsey?
Understanding what blocks him from working.
Instead of doing all his tasks' serially, he plans his tasks.
He do multiple things at the same time , and never sits idle.
Thread
A thread is basically a single process that a program can use to complete tasks. Each thread can only do a single task at once.
Link::
https://www.youtube.com/watch?v=SpmnVDYwr_g&t=223s
Task
Execution
Planning
Communication
Access
Perspective
Execution
Serial
Each task will be run sequentially; a task has to complete before the next one can be started.
Parallel
Parallel execution is executing of items are carried out simultaneously.
Planning
Single Threaded
Each task will be run sequentially; a task has to complete before the next one can be started.
Multi-threaded
Multi-threading is the execution of multiple parts of a program at the same time.
We can multi-thread on the same CPU core, or we can multi-thread on different CPU cores.
Access
Monopoly
Access memory alone
Concurrent
Can access same memory concurrently
Communication
Synchronous
Happen in real-time, waits and then proceeds
Asynchronous
Over a period of time.
Event Loop
Uses single thread but handles blocking I/Os .
So how to be the Gordon Ramsey for web?
Serial: One step at a time
Parallel: Adding many servers
Asynchronous, doing something else while waiting.
What can be done better for this application's process?
Processor sits idle as we wait for file to be read etc.
Our OS can handle that.
But what about our server request handling, what can that process do while it is sitting idle?
Understanding what blocks the process from working.
Instead of doing all his tasks serially, there should be some planning,
Multiple things at the same time will ensure server serves more at a given time.
Asynchronous Programming
Cooking in PHP and Nodejs
Callbacks
One approach to asynchronous programming is to make functions that perform a slow action take an extra argument, a callback function.
The action is started, and when it finishes, the callback function is called with the result.
Links:
https://eloquentjavascript.net/11_async.html
https://nodejs.org/en/knowledge/getting-started/control-flow/what-are-callbacks/
Callback Hells
When you depend on result of an async call, and that in turns depends on another async call and ...
Links:
https://www.freecodecamp.org/news/how-to-deal-with-nested-callbacks-and-avoid-callback-hell-1bc8dc4a2012/
Promises
Solution to callback hell
A promise represents the eventual result of an asynchronous operation.
The primary way of interacting with a promise is through its then() method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.
Links:
https://jeromejaglale.com/doc/php/laravel_asynchronous_guzzle_requests_using_promises
Async/Await
Not in PHP or in any upcoming RFC.
Brings synchronicity to async model.
But in Guzzle's Promise you can synchronously force promises to complete using a promise's wait method. When creating a promise, you can provide a wait function that is used to synchronously force a promise to complete.
Generators
Generators are like the normal functions in PHP but instead of returning a value, they yields as many values as it needs to. So, whichever function that contains “yield” is a generator.
Functions to be paused and then resumed again.
Link:
https://eloquentjavascript.net/11_async.html
Coroutines
Ability to send values back to the generator.
This is useful in asynchronous applications, as the coroutine can suspend while waiting for some task to complete or information to arrive, and the CPU is free to perform other tasks.
Fiber
Lightweight thread of execution
It maintains its own stack (variables and state), that can be started, suspended, or terminated cooperatively by the main code and the Fiber.
These are also known as coroutines or green-threads.
Links:
https://www.zend.com/blog/swoole
https://php.watch/versions/8.1/fibers
Fibers vs Threads
Fibers are a lightweight threads but not threads, but called green threads.
Green threads are "user-level threads". They are scheduled by an "ordinary" user-level process, not by the kernel.
That means fibers are cooperatively scheduled. One fiber yield itself to allow another fiber to run.
Threads are preemptively scheduled, i.e a scheduling technique that works by dividing time slots of CPU to a given process.
Links:
https://graphitemaster.github.io/fibers/
Evolution of PHP
PHP Timeline
Full Details are here: https://www.jetbrains.com/lp/php-25/
PHP State of Affairs
How we work with PHP?
How PHP compiler works?
How PHP Servers works?
How we traditionally code async?
PHP CLI
Traditional Model
https://www.zend.com/blog/exploring-new-php-jit-compiler
PHP 8 JIT
Now with JIT
Just In Time compiler transforms Opcodes into an architecture-specific machine code using DynASM
(C Library).
CPU-intensive task that will benefit the most.
https://stitcher.io/blog/php-jithttps://www.zend.com/blog/exploring-new-php-jit-compiler
https://thephp.website/en/issue/php-8-jit/
PHP HHVM
Outdated now.
HHVM compiles Hack into an intermediate bytecode. This bytecode is then translated into x64 machine code dynamically at runtime by a just-in-time (JIT) compiler.
JIT
Execution (Native)
https://www.keycdn.com/blog/php-7-vs-hhvm
PHP FPM
Traditional PHP model, is the FastCGI server implementation of PHP, like Apache, Nginx.
https://geekflare.com/php-fpm-optimization/
https://www.programmersought.com/article/79284336180/https://tsh.io/blog/php-pm-guide-getting-started-with-the-process-manager/
PHP PPM
PHP Process Manager uses ReactPHP and Symfony components.
PHP-PM basically spawns several PHP instances as worker bootstraping your application (eg. the whole Symfony Kernel) and hold it in the memory to be prepared for every incoming request.
https://web.archive.org/web/20190103202024/http://marcjschmidt.de/2014/02/08/php-high-performance/
https://github.com/php-pm/php-pm
Swoole
Runs in CLI mode, like Nodejs.
Enables the application to keep on running in memory.
PHP servers runs in a stateful manner.
Master process is the entry
Reactor threads handle client and network I/O
Manager process decides how many wokers and task workers to spwan
Task workers are use for offloaded blocking I/Os.
https://www.zend.com/blog/exploring-new-php-jit-compiler
Roadrunner
Written in Golang. It runs php application in the form of workers.
Roadrunner works by creating a HTTP server with golang’s excellent net/http package, and using Goridge as a bridge between golang and PHP to pass PSR7 Request and Responses between PHP and golang
https://roadrunner.dev/docs/intro-about
How we do async in PHP development mostly?
Jobs/ Queues
I\O bound work to queue workers
We can use curl_multi_exec() to ensure we don't have to wait for the async calls. Guzzle library is pretty much good at this.
Though we have process Forking with PHP using pcntl_fork or pthreads, but all of this can't be used in webservers, this are only while using php command line client.
PHP Async Frameworks and Libraries
Frameworks and Libraries
Guzzle
https://docs.guzzlephp.org/en/stable/
Spatie
https://github.com/spatie/async
ReactPHP
https://reactphp.org/
Amp PHP
https://amphp.org/amp/
Swoole
https://www.swoole.co.uk/how-it-works
Octane
https://github.com/laravel/octane
Framework X [Upcoming]
https://github.com/clue/framework-x/
Benchmarking
Why is such?
https://www.zend.com/blog/swoole
Swoole Coroutines
Swoole provides the powerful CSP (Communicating sequential processes) programming model with three keywords: go, chan, defer.
CSP is an alternative concurrent programming model to the actor model in Erlang or Akka. It is well known because it is adopted in Golang
Laravel Octane
How does it work?
Keeps the bootstrapped application in memory
Utilizes this server: Swoole, Roadrunner
What it brings to the table?
Concurrent Tasks
Processed by Octane utilize Swoole's "task workers", and execute within an entirely different process than the incoming request.
Cache
When using Swoole, you may leverage the Octane cache driver, which provides read and write speeds of up to 2 million operations per second. And it is interval based.
Table
Define and interact with your own arbitrary Swoole tables. Swoole tables provide extreme performance throughput and the data in these tables can be accessed by all workers on the server.
https://laravel.com/docs/8.x/octane
What be careful of?
Dependency Injections
Octane will automatically handle resetting any first-party framework state between requests. However, Octane does not always know how to reset the global state created by your application.
Must avoid injecting the application service container, HTTP request instance and configuration repository instance into the constructors of other objects.
Memory Leaks
eg. Adding data to a statically maintained array will result in a memory leak.
The future of Octane
Understand use cases for super charged applications
Making laravel packages Laravel Octane friendly
"Michelin Stars" for Async PHP in 2021?
exceptional "pattern" that is worth a special journey
excellent "pattern" that is worth a detour
a very good "pattern"
solves what it aims at consistently
Impressive track record for the last few years in production grade environment, and community is growing immensely
Follow up
Code Examples
Twitter: https://twitter.com/saadbinamjad
Github: https://github.com/saad-amjad
LinkedIn: https://www.linkedin.com/in/saadbinamjad
Thank You.
State of Async PHP
By Saad Bin Amjad
State of Async PHP
Borderless Engineering Conference 2021
- 855