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

Thank You.

State of Async PHP

By Saad Bin Amjad

State of Async PHP

Borderless Engineering Conference 2021

  • 760