PHP asynchronous programming brief

Overview

Asynchronous programming, which we literally understand, can be understood as the code is executed asynchronously. Asynchronous programming can be attributed to four modes : callbacks, event listeners, publish / subscribe, promise mode. The two modes we are most familiar with are callbacks and event listeners, giving two simplest javascript examples, an ajax, and a click event binding:

$.getJSON("uri", params, function(result) {
do_something_with_data(result);
});
$("#id").click(function(){
do_something_when_user_click_id();
});

A common feature of the above two examples is that the function is passed as a parameter to another function. The function being passed can be called a closure, and the execution of the closure depends on when the parent function calls it.

Advantages and disadvantages

Asynchronous programming has the following advantages:

  • Decoupling, you can split complex business logic into multiple event processing logic through event binding
  • Concurrency, combined with non-blocking IO, enables concurrent access to IO within a single process (or thread); for example, requesting multiple URLs, reading and writing multiple files, etc.
  • Efficiency, in the absence of an event mechanism, we often need to use polling to determine whether an event is generated.

Disadvantages of asynchronous programming:

The disadvantage of asynchronous programming is actually obvious — callback nesting. I believe some people have encountered such a scene when writing ajax:

$.getJSON("uri", params, function(result_1) {
$.getJSON("uri", result_1, function(result_2) {
$.getJSON("uri", result_2, function(result_3) {
do_something_with_data(result_3);
});
});;
});

This is often done because of data dependency issues, the second ajax request relies on the return of the first request, and the third ajax depends on the second. This causes deep callback nesting and the readability of the code drops dramatically. Although there are some frameworks that can solve such problems through some patterns, the readability of the code is still much worse than the synchronous writing.

Another disadvantage of asynchronous programming is that the process of writing and debugging is more complicated. Sometimes you don’t know when your functions will be called and the order in which they are called. And we are more accustomed to synchronous serial programming.

However, I believe that once you start using asynchronous programming, you will love this approach because it will bring you more convenience.

PHP asynchronous programming overview

In the php language, asynchronous use is not as much as in javascript. The main reason is that php generally works in the web environment, receiving requests -> reading data -> generating pages, which seems to be a serial by nature. The process; so, in php, asynchronous is not widely used.

The asynchronous programming mode in 4 in javascript can be implemented in php.

array_walk($arr, function($key, $value){
$value += 1;
});
print_r($arr);

In the case of callbacks, in most cases, the code is still executed sequentially (array_walk->print_r order). The meaning of the callback function is that the passer can call the callback function to process the data, which has the advantage of providing better scalability and decoupling. We can understand this callback function as a formatter that handles the same data. When I pass a json filter, the result returned might be a json-compressed string, when I pass an xml filter. The result returned may be an xml string (a bit polymorphic idea).

Event monitoring (timer, time event):

$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(5, function () {
$memory = memory_get_usage() / 1024;
$formatted = number_format($memory, 3).'K';
echo "Current memory usage: {$formatted}\n";
});

$loop->run();

Event listeners are not used much in PHP, but not without, such as pcntl_signal() listening for operating system signals, and monitoring of other IO events. The above example is a listener for event events, and a callback function is executed every 5 seconds.

In the four asynchronous modes, the application of event monitoring is more meaningful. However, let’s look at a synchronous example. The following code is used to make a request to Yahoo and Google (a non-existent website). The synchronization is written by first requesting Yahoo or Google, and waiting for the request to end before requesting another:

$http = new HTTP(); 
echo $http->get( 'http://www.yahoo.com' );
echo $http->get( 'http://www.google.com' );

Event-based processing can be like this:

$http = new HTTP(); 
$http->get ( 'www.yahoo.com' );
$http->get ( 'www.bing.com' );
$http->on('response', function($response){
echo $response . PHP_EOL;
});
$http->run();

Asynchronous writing allows us to process multiple transactions at the same time. Whoever processes it first will deal with who will be processed first. A simple asynchronous http client sees: async-http-php

PHP has a number of extensions and packages that provide support for this:

Ext-libevent libevent extension, based on libevent library, supports asynchronous IO and time events

Ext-event event extension, support for asynchronous IO and time events

Ext-libev libev extension, based on libev library, supports asynchronous IO and time events

Ext-eio eio extension, based on eio library, supports asynchronous disk operations

Ext-swoole swoole extension, support asynchronous IO and time, easy to write asynchronous socket server, recommended

The package-react react package provides comprehensive asynchronous programming, including IO, time events, disk IO, etc.

Package-workerman workerman package, similar to swoole, php

Publish/Subscribe:

$lookup = new nsqphp\Lookup\Nsqlookupd;
$nsq = new nsqphp\nsqphp($lookup);
$nsq->subscribe('mytopic', 'somechannel', function($msg) {
echo $msg->getId() . "\n";
})->run();

Promise:

function getJsonResult()
{
return queryApi()
->then(
// Transform API results to an object
function ($jsonResultString) {
return json_decode($jsonResultString);
},
// Transform API errors to an exception
function ($jsonErrorString) {
$object = json_decode($jsonErrorString);
throw new ApiErrorException($object->errorMessage);
}
);
}

// Here we provide no rejection handler. If the promise returned has been
// rejected, the ApiErrorException will be thrown
getJsonResult()
->done(
// Consume transformed object
function ($jsonResultObject) {
// Do something with $jsonResultObject
}
);

The meaning of the promise mode is decoupling. Just the asynchronous callback nesting problem we just mentioned can be solved by promise. The principle is that in each pass of the callback function, you will get a promie object, and this object has a then method, then method can still return a promise object, you can achieve the separation of multiple layers by passing the promise object come out. The specific code needs to study the source code, it is a bit difficult to understand, PHP recommended to read: promise

Asynchronous implementation principle

Asynchronous implementations often have loop listener events. For example, we see $loop->run() above, which is actually an infinite loop. When the event is listened to, the corresponding handler is called. If you are familiar with pcntl, you must know declare(tick=1), in fact, it is also a loop, meaning that every time you execute the tick line code, check if there is any unprocessed signal. Although there will be a blocking loop (in most cases, declare is a special case), but we can listen to multiple events, and can stop the loop during a certain event processing, so that concurrent asynchronous IO access, even more.

A pseudo code is as follows:

$async = new Async();
$async->on('request', function($requset){
do_something_with($request);
});

// This is actually the core code for $loop->run()
while(true){
$async->hasRequest() ? $async->callRequestCallback() : null;
sleep(1);
}

The whole article is actually not detailed enough. At best, it is an introductory article, which is a summary of my asynchronous programming. Learning asynchronous programming is not as simple as learning a language or design pattern. It requires us to change the traditional way of programming. Asynchronous IO is also slightly higher for learners. First you must be familiar with synchronous IO operations, or even you need to understand some protocol parsing.

I hope the above content will help some beginners. If there is something wrong in the text, I still hope to correct it.