Share
Trang chủ / Tất cả hướng dẫn / Lập trình web / Tính thời gian chạy của code

Tính thời gian chạy của code

Hướng dẫn tính thời gian chạy của code bằng cách sử dụng Symfony Stopwatch. Đây là cách tốt nhất dành cho các project phức tạp

Bên cạnh tài nguyên về bộ nhớ, thì tốc độ chạy của một hàm cũng là một phần quan trọng, nó chính là “Độ phức tạp của thuật toán” mà ta từng được dạy ở trường. Bỏ qua các yếu tố về server, thì tốc độ chạy của code chính là yếu tố ảnh hưởng trực tiếp tới tốc độ ‘First-byte’ của website. Vì vậy, khi code bạn nên debug để xác định tốc độ chạy của các hàm, thuật toán mà bạn sử dụng.

Nguyên lý vẫn là lấy thời gian sau khi chạy hàm trừ cho thời gian trước khi chạy. Và chúng ta có cách đơn giản nhất như sau :

$start = microtime(true);
while (...) {
 //Do something
}
$time_elapsed_secs = microtime(true) - $start;

Tuy nhiên bài viết này không phải để nói về điều đó, vì nó quá đơn giản và dễ hiểu. Chúng ta sẽ nói về một thư viện đến từ Symfony. Một thư viện có thể giúp bạn tính thời gian giống hệt như sử dụng đồng hồ bấm giờ – Symfony Stopwatch.

Cài đặt Symfony Stopwatch

Như các thành phần khác của Symfony, bạn có thể tự tải checkout code từ github hoặc dùng composer. Mình thì thích sử dụng composer hơn. Dưới đây là hướng dẫn cài đặt Stopwatch bằng cả hai cách :

Cài đặt bằng github:

  1. Tạo thư mục ‘StopwatchExample’
  2. Checkout code từ github bằng lệnh :
    git checkout git@github.com:symfony/Stopwatch.git .

Cài đặt bằng composer :

Tất nhiên bạn phải cài composer từ trước.

  1. Tạo thư mục ‘StopwatchExample’
  2. Giữ phím Shift + right click, chọn “Open command windows here”
  3. Chạy dòng lệnh sau :
    composer require symfony/stopwatch

Sau khi chạy xong bạn sẽ thấy như sau :

Cài stopwatch bằng composer
Cài stopwatch bằng composer

Giờ để sử dụng class này bạn cần tạo file index.php với nội dung như sau :

<?php
/**
 * Stopwatch's example
 *
 * An example show you how to use Symfony Stopwatch
 *
 * @author nguyenvanduocit
 */


require_once 'vendor/autoload.php';
require_once 'functions.php';

use Symfony\Component\Stopwatch\Stopwatch;

$stopwatch = new Stopwatch();
$stopwatch->start('example_loop');

doSomeFunction();

$event = $stopwatch->stop('example_loop');
echo $event->getDuration().'ms';

Trong đoạn code trên, ta start một event ( có thể hiểu là tên của vận động viên đang chạy ) tên là example_loop. Sau đó ta thực hiện một hàm mà bạn cần đo thời gian, cuối cùng là stop cái event mà bạn đã start. Phương thức getDuration sẽ trả về tổng thời gian của tất cả các event, ở đây ta chỉ có một event mà thôi, đơn vị ở đây là mili giây.

Sử dụng lap

Cũng như đồng hồ bấm giây bình thường, stopwatch hỗ trợ bạn tính năng lap, tính năng này cho phép bạn tạo ra các lap ( đánh dấu vòng lặp ). Xem ví dụ sau bạn sẽ hiểu :

<?php
/**
 * Stopwatch's example
 *
 * An example show you how to use Symfony Stopwatch
 *
 * @author nguyenvanduocit
 */


require_once 'vendor/autoload.php';
require_once 'functions.php';

use Symfony\Component\Stopwatch\Stopwatch;

$stopwatch = new Stopwatch();
$stopwatch->start('example_lap');
$totalLap = 10;
for($count = 0; $count <$totalLap; $count++){
	doSomeFunction();
	$stopwatch->lap('example_lap');
}

$event = $stopwatch->stop('example_lap');
$periods = $event->getPeriods();
?>
<ul>
	<?php
	foreach($periods as $index=>$period){
		echo '<li>#'.$index.':'.$period->getDuration().'ms</li>';
	}
	?>
	<li>Total time: <?php echo $event->getDuration() ?>ms</li>
	<li>The fastest runner's time: <?php echo $event->getStartTime() ?>ms</li>
	<li>Athletes slowest's time: <?php echo $event->getEndTime() ?>ms</li>
	<li>Max memmory used : <?php echo $event->getMemory() ?>ms</li>
</ul>

Kết quả sẽ như sau :

  • #0:97ms
  • #1:79ms
  • #2:79ms
  • #3:79ms
  • #4:72ms
  • #5:66ms
  • #6:66ms
  • #7:65ms
  • #8:65ms
  • #9:65ms
  • #10:0ms
  • Total time: 733ms
  • The fastest runner’s time: 0ms
  • Athletes slowest’s time: 733ms
  • Max memmory used : 524288ms

Sử dụng section

Section có thể giúp bạn nhóm các event ở những nơi rời rạc trên trang lại với nhau, Trong ví dụ dưới này, mình sẽ tạo hai section, mỗi section có nhiều event khác nhau. Sau đó ở cuối file, mình sẽ gọi các section ở trên ra, sau đó lấy các event trong các section này và show ra :

<?php
require_once 'vendor/autoload.php';
require_once 'functions.php';

use Symfony\Component\Stopwatch\Stopwatch;

$stopwatch = new Stopwatch();

$stopwatch->openSection();
$stopwatch->start('do_phase_1');
doSomeFunction();
$stopwatch->stopSection('step1');

$stopwatch->openSection();
$stopwatch->start('do_phase_1');
$totalLap = 10;
for($count = 0; $count <$totalLap; $count++){
	doSomeFunction();
	$stopwatch->lap('do_phase_1');
}
$stopwatch->stopSection('step2');


echo '<p>Step 1 :</p>';
$events_1 = $stopwatch->getSectionEvents('step1');
echo '<ul>';
foreach($events_1 as $id=> $event){
	echo '<li> phase '.$id.':'.$event->getDuration().'</li>';
}
echo '</ul>';

echo '<p>Step 2 :</p>';
$events_2 = $stopwatch->getSectionEvents('step2');
echo '<ul>';
foreach($events_2 as $id=> $event){
	echo '<li> phase '.$id.':'.$event->getDuration().'</li>';
}
echo '</ul>';

Việc này rất tiện lợi nếu như code của bạn phức tạp, có quá nhiều event, và các event này có điểm chung để có thể group lại với nhau.

Lời kết

Như bạn thấy trong các ví dụ trên đây, việc tính toán thời gian chạy của code rất đơn giản nếu nhu cầu của bạn ít, nhưng khi code phức tạp lên, nhu cầu debug tăng cao, thì việc tính toán thời gia thực thi trở nên khó kiểu soát nếu bạn chỉ sử dụng các cách đơn giản như lúc đầu. Khi đó component này của Symfony thực sự là một món bửu bối.

Bạn có thể đọc thêm thông tin và ví dụ về component này tại trang chính thức của Symfony : The Stopwatch Component.