When a user sends an invitation email to multiple friends, when a request needs to read data from many databases, when a page requires a large amount of computing and fast response, we all hope that php can implement asynchronous execution, that is, sending mails concurrently, retrieving data from multiple databases in parallel, and computing business logic in parallel, so as to quickly respond to users,
When a user sends an invitation email to multiple friends, when a request needs to read data from many databases, when a page requires a large amount of computing and fast response, we all hope that php can implement asynchronous execution, that is, sending mails concurrently, retrieving data from multiple databases in parallel, and computing business logic in parallel, so as to quickly respond to users,
Requirement
When a user sends an invitation email to multiple friends, when a request needs to read data from many databases, when a page requires a large amount of computing and fast response, we all want php to be executed asynchronously,
That is, sending mails concurrently, retrieving data from multiple databases in parallel, and computing business logic in parallel, so as to quickly respond to users without suffering.
Demand Decomposition
The demands for group mail, parallel data retrieval from the database, and parallel computing business logic are all different. Therefore, php asynchronous parallelism needs to be treated differently here.
1. Send a group email. This type of requirement generally does not need to be returned to the user after all emails are sent. Therefore, it is a requirement that needs to be processed but does not need to be returned immediately.
2. obtain data in parallel. This type of requirement is different from that of group mail. The user needs to retrieve the data from the storage before returning the data. This is an IO-intensive requirement.
3. parallel computing. These requirements are different from those of the first two, because they are not only about parallel data acquisition and waiting for results, but also about a large number of parallel computing, which is a CPU-intensive requirement.
Solution 1. How to send emails by group
There are many solutions on the Internet to solve this problem.
Simple Solution 1. If you are using php-fpm, you can use fastcgi_finish_request
2. Store such tasks in the database, and then the cron script regularly reads the tasks from the database for processing.
Reliable Solution
A reliable solution is to use message-oriented middleware, such as RabbitMQ and ZeroMQ. That is, a message queue-like mechanism is used to store such time-consuming tasks and process them one by one. Using this solution can achieve a high concurrency and stability.
2. How to obtain data in parallel
When a request needs to obtain data from many databases, the common practice in php is to read data from the database one by one in a serial manner. Therefore, a large amount of time is spent on network I/O, resulting in longer response time. How can we read data from the database in parallel or concurrently?
If the database you are using is mysql, try the asynchronous Methods mysqli_poll and mysqli_reap_async_query of mysqli extension.
The following is an example:
query("SELECT 'test'", MYSQLI_ASYNC);$all_links = array($link1);$processed = 0;do { $links = $errors = $reject = array(); foreach ($all_links as $link) { $links[] = $errors[] = $reject[] = $link; } if (!mysqli_poll($links, $errors, $reject, 1)) { continue; } foreach ($links as $link) { if ($result = $link->reap_async_query()) { print_r($result->fetch_row()); if (is_object($result)) mysqli_free_result($result); } else die(sprintf("MySQLi Error: %s", mysqli_error($link))); $processed++; }} while ($processed < count($all_links));
Through the Asynchronous Method of mysqli, you can obtain data from the database in parallel to reduce user waiting. 3. How to Achieve parallel computing
Asynchronous Parallel Computing (similar to MapReduce) is a bit complicated, which requires the use of php socket communication and process control techniques.
Principle
The principle is to allocate multiple CPU-intensive tasks to other processes (Other CPUs or other servers) for Parallel Processing (usually by distributing tasks through socket ), then, the results are summarized and displayed to the user.
Parallel Computing
How to do
1. First, there must be multiple socket services that can be called remotely. Generally, we call it RpcServer. It has three main tasks: receiving requests, processing requests, and sending results, which are similar to our common WebServer. The caller notifies the RpcServer of the task to be processed through certain url rules and GET/POST parameters. After the RpcServer completes processing, the result is returned to the caller.
2. The caller concurrently requests the task to RpcServer. If your RpcServer uses the HTTP protocol, this step is better implemented.
You can use the php curl_multi _ * function.
3. Round-Robin whether data of each RpcServer is returned. Using the HTTP protocol, you can use the php curl_multi _ * function.
HTTP call demo
In fact, the HTTP protocol is not very suitable for remote calls, because the HTTP header contains a large amount of unused HTTP header information, occupying a large amount of bandwidth, and it is difficult to achieve long links.
Here we recommend a ready-made RPC framework workerman-jsonrpc, which is very useful and strongly recommended.
The usage is as follows:
Create a file./applications/JsonRpc/Services/User. php
class User
{
public static function getInfoByUid($uid)
{
// ....
}
public static function getEmail($uid)
{
// ...
}
}
Start the server as follows:./bin/workermand start
The client uses the sample client to synchronously call
Include_once 'yourclientdir/RpcClient. php ';
$ Address_array = array (
'Tcp: // 127.0.0.1: 8080 ',
'Tcp: // 127.0.0.1: 8080'
);
// Configure the server list
RpcClient: config ($ address_array );
$ Uid = 567;
// User corresponds to the User class in applications/JsonRpc/Services/User. php
$ User_client = RpcClient: instance ('user ');
// GetInfoByUid corresponds to the getInfoByUid method in the User class
$ Ret_sync = $ user_client-> getInfoByUid ($ uid );
Asynchronous client call
Include_once 'yourclientdir/RpcClient. php ';
// Server list
$ Address_array = array (
'Tcp: // 127.0.0.1: 8080 ',
'Tcp: // 127.0.0.1: 8080'
);
// Configure the server list
RpcClient: config ($ address_array );
$ Uid = 567;
$ User_client = RpcClient: instance ('user ');
// Call the User: getInfoByUid method Asynchronously
$ User_client-> asend_getInfoByUid ($ uid );
// Call the User: getEmail method asynchronously.
$ User_client-> asend_getEmail ($ uid );
Here is Other Business Code
....................
....................
// Receives data asynchronously when data is needed
$ Ret_async1 = $ user_client-> arecv_getEmail ($ uid );
$ Ret_async2 = $ user_client-> arecv_getInfoByUid ($ uid );
Here are other business logic
This framework integrates the monitoring module to display information such as the number of API calls, success rate, interface time consumption, and error logs.The access http: // ip: 33737 interface is similar to the following:
Framework:
Simple and efficient json Protocol version workerman-JsonRpc
Multi-platform friendly thrift version workerman-Thrift