- vừa được xem lúc

Tìm hiểu Lazy Collection

0 0 42

Người đăng: Trần Đào Mạnh

Theo Viblo Asia

Introduction

Lazy Collection là một tính năng mới của Laravel được giới thiệu trong phiên bản 6.0. Đây là một sự bổ sung cho tính năng Collection vô cùng hữu ích đã có trước đó của Laravel cho phép ta giảm thiểu bộ nhớ sử dụng. Vì là một tính năng mới, hiện các tài liệu về Lazy Collection vẫn còn hạn hẹp nên mình xin phép góp vui một bài viết đi vào tìm hiểu về Lazy Collection và có một cái nhìn vào cách nó hoạt động thông qua PHP Generators.

Mục lục

  • I. Lazy Collection
  • II. PHP Generators

I. Lazy Collection

1. Giới thiệu

Trong các bài toán thực tế, chúng ta sẽ có thể gặp các tình huống cần làm việc với một lượng lớn các bản ghi như dữ liệu về log hay notifications. Tuy nhiên, việc lấy ra số lượng lớn như vậy để làm việc với Collection thì không khả thi chút nào, đặc biệt với các hệ thống đã chạy lâu năm. Chương trình của chúng ta được triển khai trên một server vật lý với dung lượng RAM giới hạn, việc đọc một lượng lớn các bản ghi sẽ khiến server nhanh chóng quá tải và gây chết trang. Để giảm thiểu vấn đề này, Laravel đã cho ra đời Lazy Collection.

2. Sử dụng

a. Tổng quát

Lazy Collection là một tính năng mới được thêm vào phiên bản Laravel 6.0 cho phép ta làm việc với bộ dữ liệu lớn và duy trì bộ nhớ sử dụng lợi dụng PHP Generators.

b. Khởi tạo Lazy Collection

Tương tự như Collection, để sử dụng LazyCollection ta có thể thêm use Illuminate\Support\LazyCollection vào đầu file.

VD:

use Illuminate\Support\LazyCollection; LazyCollection::make(function () { $handle = fopen('log.txt', 'r'); while (($line = fgets($handle)) !== false) { yield $line; }
});

Bên cạnh đó, query builder cũng cung cấp cho chúng ta hàm cursor() trả về một LazyCollection cho phép ta làm việc trên nhiều bản ghi nhưng không phải tải toàn bộ vào bộ nhớ cùng lúc.

VD: Giả sử chúng ta có 100,000 bản ghi log hệ thống cần xử lý.

use App\Models\Log; // không dùng lazy collection, truy vấn thực hiện lấy toàn bộ 100,000 bản ghi vào RAM
Log::all()->map(function ($log, $key) { return parseMessage($log->message);
}); // sử dụng lazy collection, lần lượt từng model được thêm vào bộ nhớ nhưng chỉ cần 1 query
Log::cursor()->map(function ($log, $key) { return parseMessage($log->message);
}); 

c. Các phương thức

Giống với Collection, Lazy Collection implement Illuminate\Support\Enumerable và cung cấp đầy đủ các phương thức thông thường như all(), map(), sort(), where(), v.v... Mọi người có thể xem chi tiết trong tài liệu tham khảo.

Tuy nhiên, bên cạnh đó LazyCollection cũng bao gồm các phương thức mới như:

  • takeUntilTimeout(DateTimeInterface $timeout): Hàm sẽ thực hiện lấy ra các giá trị tới khi hết thời gian. (LƯU Ý: phương thức này có từ bản 8.x)
  • tapEach(callable $callback): gần giống với each(), phương thức sẽ thực hiện hàm callback cho từng item nhưng chỉ thực hiện lần lượt cho từng item khi được lấy ra một cách "lazy".
  • remember(): ghi nhớ các giá trị đã được lấy ra và bỏ qua chúng khi gặp lại.

II. PHP Generators

Như đã nêu trên, để Lazy Collection có thể thực hiện lấy lần lượt các bản ghi vào bộ nhớ chúng ta sử dụng PHP Generator. Một hàm generator nhìn qua không khác so với một PHP function thông thường ngoại trừ việc sử dụng yield thay vì return. Vậy sự khác biệt là gì?

Giả sử ta có một hàm countToMillion() được cài đặt như sau

function countToMillion()
{ for($i = 1; $i <= 1000000; $i++) { return $i; }
} dump(countToMillion());

Output:

1

Hàm thực hiện trả về giá trị đầu tiên và dừng hoàn toàn countToMillion(). Nếu ta thay đổi từ khóa return sang yield, ta sẽ có như sau:

function countToMillion()
{ for($i = 1; $i <= 1000000; $i++) { yield $i; }
} dump(countToMillion());

Output:

Generator {#1534 ▼ executing: { ... } closed: false
}

Như ta thấy, từ khóa yield sẽ trả về một Generator object thay vì giá trị "1". Vậy Generator object này có gì đặc biệt?

Tìm hiểu tiếp theo ta sẽ thử thực hiện in lần lượt từng số đếm tới 1 triệu. Để làm được điều đó sử dụng return chúng ta sẽ cần phải lưu lại 1,000,000 bản ghi vào một biến số trước khi trả về.

function countToMillion()
{ $data = []; for($i = 1; $i <= 1000000; $i++) { $data[] = $i; } return $data;
} foreach (countToMillion() as $number) { dump($number);
}

Output:

1
2
3
...
1000000

Điều này gây tốn rất nhiều bộ nhớ. Nhưng khác với return, yield không thực sự dừng hoàn toàn phương thức của chúng ta mà thay vào đó tạm dừng ở vị trí đang đứng. Sử dụng Generator object chúng ta có thể thực hiện lặp qua từng yield để lấy giá trị tiếp theo trả về và giải phóng bộ nhớ sau khi hoàn thành.

// count with yield
...
foreach (countToMillion() as $number) { dump($number);
}

Output:

1
2
3
...
1000000

Dựa trên ý tưởng này, Laravel Lazy Collection thực hiện xử lý lần lượt các item trong Collection thay vì lưu tất cả vào bộ nhớ.

Tổng kết

Vậy qua bài viết trên chúng ta đã hiểu được cách sử dụng của Lazy Collection và có một cái nhìn sâu hơn về cách nó hoạt động thông qua PHP Generators.

Tài liệu tham khảo

  1. https://www.php.net/manual/en/language.generators.syntax.php
  2. https://laravel.com/docs/8.x/collections#introduction

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 416

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 469

- vừa được xem lúc

Sử dụng Swagger để xây dựng API documentation

Giới thiệu về Swagger. RESTful API là một tiêu chuẩn dùng trong việc thiết kế API cho các ứng dụng web (thiết kế Web services) để tiện cho việc quản lý các resource.

0 0 1k

- vừa được xem lúc

So sánh Interface và Abstract trong lập trình hướng đối tượng.

Tổng quan. Interface và Abstract class là 2 khái niệm cơ bản trong lập trình OOP.

0 0 63

- vừa được xem lúc

CURL và cách sử dụng trong PHP

Giới Thiệu. CURL là bộ thư viện được sử dụng để giúp thực hiện việc chuyển dữ liệu thông qua nhiều giao thức khác nhau (như HTTP, FPT...). Với giao thức HTTP, cURL hỗ trợ việc gửi dữ liệu sử dụng tất cả các phương thức hiện có như GET, POST, PUT, DELETE... cURL cũng hỗ trợ việc chuyền dữ liệu sử dụn

0 0 93

- vừa được xem lúc

Thêm dòng dữ liệu mới (MySQL) trong Laravel

Chào các bạn, Laravel hiện đang là hot trend trong "thế giới PHP". 1. Cấu hình cơ bản ban đầu. .

0 0 51