LinQ Performance - "multiple enumerations" khi sử dụng IEnumerable
Trong các dự án thực tế, khi viết các phương thức dùng chung cho các yêu cầu khác nhau, với các phương thức liên quan đến tập hợp (array, collection, list), các lập trình viên thường sử dụng IEnumerable<T>. Phương thức này cơ bản có dạng như sau:
public IEnumerable<T> GetTObjects()
{
//do something
//IEnumerable<T> result = ....;
//return result;
}
Sau đó, ở các phương thức khác chỉ cần gọi phương thức GetTObjects() và tiếp tục xử lý tập hợp. Với tập hợp này, do yêu cầu nghiệp vụ, chúng ta phải xử lý 1 chuỗi câu lệnh như kiểm tra tập hợp rỗng, tìm các phần tử thỏa mãn 1 điều kiện nào đó, loại bỏ bớt phần tử theo điều kiện nào đó... Và trong rất nhiều trường hợp như thế này, chúng ta thường hay gặp cách viết mã chương trình theo dạng như sau:
public void ProcessTObjects(){
var objects = GetTObjects();
if(!objects.Any()){
//do something
}
var object = objects.FirstOrDefault(Func<T, bool> samplePredicate);
if(object != null) {
//do something
}
var otherObjects = objects.Where(Func<T, bool> samplePredicate);
foreach(var obj in otherObjects){
//do something
}
//more code ...
}
Cách viết này theo nghiệp vụ là ok và đúng logic rồi. Tuy nhiên, dạng code theo cách như trên sẽ gây ra 'Multiple Enumerations', hiểu 1 cách đơn giản là IEnumerable<T> được evaluate lại nhiều lần và như vậy sẽ làm giảm performance của chương trình. Trong đoạn mã dạng trên, sẽ có ít nhất 3 lần IEnumerable<T> được evaluate:
- Lần 1 là dòng code sử dụng phương thức Any().
- Lần 2 là dòng code sử dụng phương thức FirstOrDefault().
- Lần 3 là dòng code sử dụng phương thức Where().
Để tránh điều này xảy ra, chúng ta phải làm cho IEnumerable<T> được evaluate 1 lần duy nhất trong phương thức trên. Để thực hiện điều này, chúng ta nên cast IEnumerable<T> sang dạng List<T> hoặc Array<T> ngay tại thời điểm lấy về IEnumerable<T>. Cụ thể ở đây, chúng ta sửa như sau:
Chuyển: 'var objects = GetTObjects()' thành 'var objects = GetTObjects().ToList()' hoặc 'var objects = GetTObjects().ToArray()'
Với cách xử lý này, ở các đoạn code tiếp theo, chúng ta sẽ làm việc với List<T> hoặc Array<T>, chứ không còn phải làm việc với IEnumerable<T> nữa, và đảm bảo được IEnumerable<T> chỉ được evaluate 1 lần duy nhất.
Các bạn có thể chuyển đoạn code sang 1 chương trình cụ thể và test thử để xem hiệu quả. Ngoài ra, để nắm vững các kiến thức về LINQ cũng như tránh được các lỗi trong LINQ theo dạng code như trong bài viết đã đề cập, các bạn nên tìm hiểu Deffered Execution và Immediate Execution trong linQ hoặc có thể tham dự khóa học về LINQ của trang tedu.
Tác giả: Nguyễn Thanh Sơn
Chú ý: Tất cả các bài viết trên TEDU.COM.VN đều thuộc bản quyền TEDU, yêu cầu dẫn nguồn khi trích lại trên website khác.
Bài viết liên quan
Sử dụng kiểu tập hợp (Enum)
Enum (viết tắt của Enumeration) trong C# là một kiểu dữ liệu đặc biệt cho phép bạn định nghĩa một tập hợp các hằng số có tên
Đọc thêmTính đóng gói (Encapsulation) và best practices trong OOP
(Tính đóng gói) là một trong những nguyên tắc cơ bản của lập trình hướng đối tượng (OOP).
Đọc thêmTính trừu tượng - Abstract classes and interfaces
Tính trừu tượng (Abstraction) trong OOP là kỹ thuật ẩn đi các chi tiết triển khai và chỉ hiển thị cho người dùng những chức năng cần thiết.
Đọc thêmTính chất kế thừa (Inheritance) và đa hình (polymorphism)
Kế thừa là cơ chế cho phép một lớp (class) kế thừa các thuộc tính và phương thức từ một lớp khác.
Đọc thêmCách debug ứng dụng C#
Hướng dẫn cách debug chương trình C# trong Visual Studio và Visual Studio Code
Đọc thêmTìm hiểu về các loại Collection trong C#
Trong C#, collections là các cấu trúc dữ liệu được sử dụng để lưu trữ và quản lý các nhóm đối tượng. C# cung cấp nhiều loại collections khác nhau để phù hợp với các yêu cầu cụ thể của lập trình viên
Đọc thêmTổng quan về Generic và Non-Generic Collection
Hiểu khái niệm Generic và Non-Generic Collection và phân biệt giữa Generic Collection và Non-Generic Collection.
Đọc thêmSử dụng mảng (Arrays)
Mảng trong C# là một cấu trúc dữ liệu lưu trữ một dãy các phần tử có bộ nhớ nằm liên tiếp nhau và có kích thước cố đinh.
Đọc thêmLập trình hướng đối tượng
Lập trình hướng đối tượng (Object Oriented Programing) hay còn gọi là OOP. Là một kỹ thuật lập trình cho phép các lập trình viên có thể ánh xạ các thực thể bên ngoài đời thực và trừu tượng hoá thành các class và object trong mã nguồn.
Đọc thêmVòng lặp (loop)
Trong thực tế khi bạn cần thực thi một khối lệnh nhiều lần. Vòng lặp cho phép chúng ta thực thi một câu lệnh hoặc một khối lệnh nhiều lần.
Đọc thêm