Performance optimization of PHP applications
The biggest benefit of programming in PHP is how easy it is to learn this programming language and its rich libraries. Even if we don't know much about the functions we need to use, we can guess how to accomplish a specific task.
Although PHP is very simple and easy to learn, we still need to spend a little time learning some programming skills of PHP, especially those related to performance and memory usage. In PHP, there are many tricks that allow us to reduce memory usage and improve application performance. In this article, we will briefly introduce the analysis of PHP applications, how to change the script code, and compare various parameter values before and after optimization.
By setting timing procedures in the program and executing these codes repeatedly, we can obtain a set of data about the execution speed of the program. This data can be used to discover bottlenecks in the program and how to optimize it to improve the performance of the application.
Maybe readers have heard of the PEAR library. We will use the PEAR library to create examples that we need to use during analysis. This is also the easiest way to analyze existing code. It allows us to analyze the code without using commercial products.
The name of the library we are going to use is PEAR::Benchmark and it is very useful for profiling and performance testing the code. This library provides a class named Benchmark_Timer(), which can record the time between one function call and the next function call. When testing the performance of the code, we can get a detailed script execution result, which is very simple, as follows:
include_once("Benchmark/Timer.php");
$bench = new Benchmark_Timer;
$bench->start();
$bench-> setMarker('Start of the script');
// Now in sleep state for a few minutes
sleep(5);
$bench->stop();
// Get analysis information from timer
print_r($bench->getProfiling());
?>
The output after executing the above code is as follows:
Array
(
[0] => Array
(
[name] => Start
[time] => 1013214253.05751200
[diff] => -
[total] => 0
)
[1] => Array
(
[name] => Start of the script
[time] => 1013214253.05761100
[diff] => 9.8943710327148E-05
[total] => 9.8943710327148E-05
)
[2] => Array
(
[name] => Stop
[time] => 1013214258.04920700
[diff] => 4.9915959835052
[total] => 4.9916949272156
)
)
The numbers above may seem like a disjointed set of numbers, but if the size of the program is larger, these numbers can be very useful.
Perhaps the majority of readers can also guess that the first entry in the array is the actual method of calling the Benchmark_Timer() class, for example
$bench->start(), $bench->setMarker() and $bench->stop(). The numbers associated with these entries are quite simple. Now let’s take a closer look at these numbers:
[0] => Array
(
[name] => Start
[time] => 1013214253.05751200
[diff] => -
[total] => 0
)
The time entry refers to the UNIX timestamp when the start() method of Benchmark_Timer() is called. The diff entry indicates the time interval between this call and the last call. Since there is no previous call here, a Dash, the total entry refers to the total time the code has been running since the start of the test until this particular call. Let's take a look at the output of the next array:
[1] => Array
(
[name] => Start of the script
[time] => 1013214253.05761100
[diff] => 9.8943710327148E-05
[total] => 9.8943710327148E-05
)
From the above numbers we can see that after calling $bench->start(), the program runs for 9.8943710327148E-05 seconds (that is, 0.0000989 seconds) before calling $bench->setMarker(….).
A real performance testing experience
While the above example is good, it's really not a good example for deciding how to optimize your site's code design. Below I will use my own personal experience as a website technician to illustrate how to solve performance problems.
I don't really understand the code used by the website, because it was developed over many years based on specific needs - one module contains the website conversion code, another module records the usage of the website, and the other modules have their own The role of each. The main developer of the website and I both realized that the website's code needed to be optimized, but we didn't know what the problem was.
In order to complete the task as quickly as possible, I started to study the main script code of the website, and added some $bench->setMarker() commands to all script codes and their included files, then analyzed the output of $bench->getProfiling(), and I was surprised by the results. It turned out that the problem lay in a function call related to the conversion code to obtain a specific language name (such as en for english), which was used hundreds of times on each page. Each time this function is called, the script code queries a MySQL database to obtain the actual language name from a database table.
So we create a buffering system for this type of information. After just 2 days of work, we greatly improved the performance of the system, and the number of page views increased by 40% in the first week. Of course, this is just one example of how analyzing code can improve the performance of an Internet application or Internet website.
Performance test function call
Although Benchmark_Timer() is particularly useful when analyzing a script or web page (and its containing files), it is not scientific because we must load the script multiple times to obtain the analyzed data, and it is not specific to a certain class or function. called.
Another class in the PEAR::Benchmark library called Benchmark_Iterator can solve this problem very well. It can display analysis information for a specific function or class method. Its purpose is to be able to get consistent results from tests because we know that if we run a script once and it takes 10 seconds to run, that doesn't mean it will always take 10 seconds to run every time.
In any case, let's see some examples:
// Code to connect to the database
include_once("DB.php");
$dsn = array(
'phptype' => 'mysql',
'hostspec' => 'localhost',
'database' => 'database_name',
'username' => 'user_name',
'password' => 'password'
);
$dbh = DB::connect($dsn);
function getCreatedDate($id)
{
global $dbh;
> $stmt = "SELECT created_date FROM users WHERE id=$id";
// Use PEAR::DB here
$created_date = $dbh-> getOne($stmt);
if ((PEAR::isError($created_date)) ||
(empty($created_date))) {
return false;
} else {
return $created_date;
}
}
include_once 'Benchmark/Iterate.php';
$bench = new Benchmark_Iterate;
//Run the getDate function 10 times
$bench-> run(10, 'getCreatedDate', 1);
//Print analysis information
print_r($bench->get());
?>
Running the above code produces results similar to the following:
Array
(
[1] => 0.055413007736206
[2] => 0.0012860298156738
[3] => 0.0010279417037964
[4] => 0.00093603134155273
[5] => 0.00094103813171387
[6] => 0.00092899799346924
[7] => 0.0010659694671631
[8] => 0.00096404552459717
[9] => 0.0010690689086914
[10] => 0.00093603134155273
[mean] => 0.0064568161964417
[iterations] => 10
)
The above numbers are easy to understand. The mean entry represents the average time of 10 runs of the getCreatedDate() function. In actual testing, you should run it at least 1000 times, but the results from this example are enough to illustrate the problem.