DANH MỤC: PHP OPTIMIZE

Generators trong PHP có gì đặc biệt?


Tiếp tục với series tối ưu hệ thống, bài này chúng ta sẽ cùng đi vào tìm hiểu về PHP gennerators xem nó gì đặc biệt không mà giang hồ đồn nhiều về nó thế.

1, Generators là gì?

-Generator là thuật ngữ được PHP hỗ trợ từ phiên bản 5.5 trở lên, nó hỗ trợ chúng ta có thể truy xuất dến dữ liệu trong mảng mà không cần lưu trữ mảng trên bộ nhớ (nghe có vẻ hay đấy nhỉ).

-Để sử dụng generators thì chúng ta sẽ dùng từ khóa yield (Không được nhầm với yield trong laravel đâu nhé) thay cho return thông thường. Ok, về lí thuyết thì như thế giờ chúng ta cùng đi sâu vào trong các ví dụ để tìm hiểu xem nó có lợi, hại gì?

2, So Sánh.

-Đầu tiên mình sẽ so sánh tốc độ xử lý và độ hao tốn bộ nhớ của phương pháp thông thường và generators trong PHP với vòng lặp 1.000.000 lần.

+Phương pháp thông thường.

<?php

$start_time = microtime(true);
$array = array();
$result = '';

for ($count = 1000000; $count >= 0; $count--) {
    $array[] = $count / 2;
}

foreach ($array as $val) {
    $val += 145.56;
    $result .= $val;
}

$end_time = microtime(true);

echo "Thực thi trong (đơn vị giây): ", bcsub($end_time, $start_time, 4), "<br>";
echo "Tốn bộ nhớ (đơn vị bytes): ", memory_get_peak_usage(true), "<br/>";

Sau khi chạy mình thu được kết quả:

Thực thi trong (đơn vị giây): 1.8427
Tốn bộ nhớ (đơn vị bytes): 93585408

+Sử dụng generators.

<?php

$start_time = microtime(true);
$result = '';

function it()
{
    for ($count = 1000000; $count >= 0; $count--) {
        yield $count / 2;
    }
}

foreach (it() as $val) {
    $val += 145.56;
    $result .= $val;
}

$end_time = microtime(true);

echo "Thực thi trong (đơn vị giây): ", bcsub($end_time, $start_time, 4), "<br>";
echo "Tốn bộ nhớ (đơn vị bytes): ", memory_get_peak_usage(true), "<br/>";

Và kết quả mình thu được: 

Thực thi trong (đơn vị giây): 1.7983
Tốn bộ nhớ (đơn vị bytes): 9175040

-Tiếp tục để rõ hơn thì mình sẽ thử nó ở dữ liệu lơn hơn nữa xem sao. Cụ thể mình sẽ thêm 1 con số 0 vào trong count để nó thành 10 triệu

+Phương pháp thông thường.

<?php
$start_time = microtime(true);
$array = array();
$result = '';

for ($count = 10000000; $count >= 0; $count--) {
    $array[] = $count / 2;
}

foreach ($array as $val) {
    $val += 145.56;
    $result .= $val;
}

$end_time = microtime(true);

echo "Thực thi trong (đơn vị giây): ", bcsub($end_time, $start_time, 4), "<br>";
echo "Tốn bộ nhớ (đơn vị bytes): ", memory_get_peak_usage(true), "<br/>";

Và kết quả:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 24 bytes)

+Dùng Generators:

<?php
ini_set('max_execution_time', 300);
$start_time = microtime(true);
$result = '';

function it()
{
    for ($count = 10000000; $count >= 0; $count--) {
        yield $count / 2;
    }
}

foreach (it() as $val) {
    $val += 145.56;
    $result .= $val;
}

$end_time = microtime(true);

echo "Thực thi trong (đơn vị giây): ", bcsub($end_time, $start_time, 4), "<br>";
echo "Tốn bộ nhớ (đơn vị bytes): ", memory_get_peak_usage(true), "<br/>";

Và kết quả:

Thực thi trong (đơn vị giây): 37.0833
Tốn bộ nhớ (đơn vị bytes): 98041856

Kết Luận: Như vậy các bạn đã thấy, khi dùng generator thì hệ thống có vẻ chạy nhanh hơnbớt hao tổn tài nguyên hơn

3, Mảng trong generators.

-Trong generator chúng ta cũng có thể truy vấn theo kiểu mảng.

VD: Dùng foreach để lặp hết key và value của mảng generators.

<?php
$data = [
    'Toidicode.com',
    'Học Lập trình online'
];

function getGen($array = [])
{
    for ($i = 0; $i < count($array); $i++) {
        //truyền data vào generators
        yield $i => $array[$i];
    }
}

//hiển thị generators 
foreach (getGen($data) as $key => $value) {
    echo 'Phần tử thứ ' . $key . ' có giá trị là: ' . $value . '<br>';
}

Kết quả:

Phần tử thứ 0 có giá trị là: Toidicode.com
Phần tử thứ 1 có giá trị là: Học Lập trình online

VD: Hoặc chúng ta cũng có thể dùng đối tượng dể lấy ra key và value của generator.

<?php

function Gen()
{
    yield 'toidicode.com' => 'Học lập trình online miễn phí';
}

$gen = Gen();

echo "{$gen->key()} => {$gen->current()}";

Kết quả:

toidicode.com => Học lập trình online miễn phí

4, Đối tượng generators.

-Đồng thời bạn cũng có thể dùng object đối với generator.

Thêm giá trị

-Để thêm giá trị cho generators chúng ta dùng phương thức send().

VD:

<?php

function printer()
{
    echo 'Toidicode.com <br>';

    while (true) {
        $string = yield;
        echo $string.'<br/>';
    }
}

$printer = printer();

$printer->send('Học Lập trình');
$printer->send('Miễn phí');

Kết quả:

Toidicode.com 
Học Lập trình
Miễn phí

Kiểm tra generators đã được đóng chưa.

-Để kiểm tra generator đã được đóng chưa chúng ta dùng hàm valid(). Hàm này trả về true nếu đã được đóng và false nếu chưa được đóng.

VD:

<?php

function printer()
{
    while (true) {
        $string = yield;
    }
}

$printer = printer();

if ($printer->valid()) {
	echo 'Đã được đóng';
} else{
	echo 'Chưa dược đóng';
}

Kết quả:

Đã được đóng

5, Lời kết.

-Phần trên mình ví dụ trên phiên bản PHP5.6.21, nếu các bạn ví dụ trên các phiên bản khác có thể kết quả nó sẽ khác đi một chút.

-Về phần generators đối tượng thì nó còn hỗ trợ một số phương thức khác các bạn có thể xem thêm tại đây.

Nguồn: Toidicode.com

Thông tin tác giả

Vũ Thanh Tài

Vũ Thanh Tài

Biển học vô biên, quay đầu là dại!

Hãy tham gia group facebook để cùng giao lưu chia sẻ kiến thức! Tham Gia