Sử dụng PHP Generators trong cải thiện hiệu năng của ứng dụng web
Chào các bạn, như chúng ta đã biết, tốc độ của một trang web liên quan trực tiếp đến trải nghiệm của người dùng. Nó làm nên sự khác biệt giữa một ứng dụng web tốt và một ứng dụng web hoàn hảo. Chính vì thế, ở vị trí của một developer, chúng ta luôn luôn mong muốn tìm mọi cách để cải thiện hiệu năng ...
Chào các bạn, như chúng ta đã biết, tốc độ của một trang web liên quan trực tiếp đến trải nghiệm của người dùng. Nó làm nên sự khác biệt giữa một ứng dụng web tốt và một ứng dụng web hoàn hảo. Chính vì thế, ở vị trí của một developer, chúng ta luôn luôn mong muốn tìm mọi cách để cải thiện hiệu năng của sản phẩm mà chúng ta làm ra. Có chút gì đó lan man không nhỉ, chúng ta đang nói về PHP Generators cơ mà, sao lại bàn đến hiệu năng và tốc độ ở đây nhỉ. Vâng, trong khá nhiều cách để cải thiện hiệu năng của một trang web tốt hơn, hôm nay mình xin được giới thiệu đến các bạn một phương pháp tối ưu hóa hiệu năng trực tiếp trong code. Đó là sử dụng PHP Generators. Chúng ta cùng nhau bắt đầu nhé.
PHP Generators là gì?
Bắt đầu từ version 5.5, PHP cung cấp cho chúng ta một phương pháp mới để truy nhập đến dữ liệu trong một mảng mà không cần lưu trữ tất cả các phần tử của mảng trong không gian bộ nhớ gọi là các hàm Generators. Vẫn có một chút khó hiểu phải không? Chúng ta sẽ cùng nhau xem qua một ví dụ sau để rõ hơn về vấn đề này.
Đầu tiên, trên server của chúng ta cần tạo một file tên là generator.php và chúng ta sẽ sử dụng nó xuyên suốt bài này. Sau khi tạo file chúng ta hãy thêm một số dòng code như sau:
<?php function getRange ($max = 10) { $array = []; for ($i = 1; $i < $max; $i++) { $array[] = $i; } return $array; } foreach (getRange(15) as $range) { echo "Dataset {$range} <br>"; }
Sau đó chúng ta hãy khởi động server đã cài đặt PHP
php -S localhost:8000
Khởi động trình duyệt và vào địa chỉ http://localhost:8000/generator.php chúng ta sẽ thấy kết quả của đoạn chương trình trên như sau:
Ồ, có vẻ như mọi thứ chưa có gì bất ổn lắm cho đến một ngày đẹp trời chúng ta thử khởi tạo hàm getRange() của chúng ta với một số vô cùng lớn. Chẳng hạn như thay đổi ở trong vòng foreach() như sau:
foreach (getRange(PHP_INT_MAX) as $range) { echo "Dataset {$range} <br>"; }
Lúc này chúng ta thấy hàm getRange(PHP_INT_MAX) được truyền vào là giá trị số nguyên cực đại mà version PHP hiện tại cung cấp. Thử chạy lại trình duyệt chúng ta sẽ thấy một thông báo lỗi không mấy tươi đẹp như sau:
Thông báo trên cho chúng ta biết rằng PHP server của chúng ta đang bị tràn bộ nhớ. Có một giải pháp cho vấn đề này chúng ta có thể nghĩ đến đó là chỉnh sửa trong file php.ini để tăng tham số memory_limit. Nhưng chúng ta hãy tự hỏi xem đó thật sự đã phải là giải pháp tối ưu chưa, rõ ràng chúng ta đang nhận thấy một vấn đề ở đây là chỉ cần một đoạn code nhỏ đã có thể chiếm trọn tài nguyên bộ nhớ của bạn. Điều đó thật sự là một điều không thể chấp nhận được. Vậy giải pháp cho vấn đề này là gì? Chúng ta sẽ cùng nhau tìm hiểu trong phần tiếp theo nhé.
Sử dung PHP Generators
Bây giờ chúng ta thử định nghĩa lại hàm getRange() như trên có sử dụng Generators như sau:
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { yield $i; } } foreach (getRange(PHP_INT_MAX) as $range) { echo "Dataset {$range} <br>"; }
Bây giờ chúng ta hãy để ý đến hàm getRange() chúng ta chỉ lặp qua các giá trị của biến $i rồi trả về kết quả với từ khóa yield. Một cách đơn giản chúng ta có thể hiểu yield có chức năng tương tự như return đều là trả về giá trị của một hàm. Tuy nhiên yield trả về giá trị khi giá trị đó cần sử dụng đến mà không lưu trữ tất cả các giá trị trong bộ nhớ. Sau khi viết lại hàm trên chúng ta có thể chạy lại trình duyệt và xem kết quả.
Đã không còn lỗi tràn bộ nhớ, trong một thời gian cho phép trình duyệt đã hiển thị được kết quả như chúng ta mong muốn. Có thể thấy được bản thân PHP Generators đóng vai trò quan trọng trong tiết kiệm không gian bộ nhớ.
Note: Một lưu ý nhỏ rằng chúng ta chỉ có thể sử dụng generators trong một hàm
Tại sao nên sử dụng Generators
Trong rất nhiều trường hợp chúng ta muốn xử lý một tập dữ liệu rất lớn (ví dụ như dữ liệu từ các file log hệ thống) hoặc muốn tính toán xử lý trên một mảng với vô cùng lớn các phần tử. Rõ ràng chúng ta không hề muốn việc xử lý trên các tập dữ liệu đó chiếm dụng một lượng lớn thậm chí là tất cả bộ nhớ của chúng ta và việc nên làm là tìm cách tiết kiệm bộ nhớ càng nhiều càng tốt. Thay vì phải lưu trữ cả một tập dữ liệu lớn như vậy, chúng ta có thể sử dụng các generators để lấy ra các dữ liệu nào cần thiết.
Returning Keys
Trong một vài trường hợp, dữ liệu của chúng ta thực sự có ý nghĩa khi được biểu diễn dưới dạng key => value và trong khi sử dụng generators chúng ta cũng có thể trả về theo dạng đó bằng cách sau:
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { $value = $i * mt_rand(); yield $i => $value; } }
Sau đó chúng ta có thể sử dụng cặp giá trị key => value như sau:
<?php foreach (getRange(PHP_INT_MAX) as $range => $value) { echo "Dataset {$range} has {$value} value<br>"; }
Truyền tham số và trong Generators
Giả sử như chúng ta muốn thêm một vài tham số để quy định cách hoạt động của Generators ví dụ như thêm điều kiện dừng cho Generators chẳng hạn. Chúng ta thực hiện nó như sau:
<?php function getRange ($max = 10) { for ($i = 1; $i < $max; $i++) { $injected = yield $i; if ($injected === 'stop') return; } }
Và để thêm giá trị injected vào trong hàm getRange() chúng ta thực hiện như sau:
<?php $generator = getRange(PHP_INT_MAX); foreach ($generator as $range) { if ($range === 10000) { $generator->send('stop'); } echo "Dataset {$range} <br>"; }
Note: Chúng ta có thể sử dụng từ khóa return để kết thúc mọi xử lý trong Generators
Kết luận
Generators cung cấp một giải pháp mạnh mẽ cho việc tiết kiệm hiệu năng của server, từ đó khiến cho việc xử lý của server trở nên nhẹ nhàng hơn đồng nghĩa với việc chúng ta không nhất thiết phải có phần cứng tốt mới có thể tăng tốc độ của trang web. Tuy nhiên không nên quá lạm dụng nó vì rất có thể nó sẽ gây ra các vấn đề nghiêm trọng hơn cho hệ thống của bạn nếu sử dụng sai
Tham khảo
Understanding PHP Generators
Generators overview