+1

Async vs. Isolate trong Flutter: Song song hóa trong Flutter

Tóm tắt

Tôi sẽ làm rõ sự nhầm lẫn giữa async và isolates, nhấn mạnh sự khác biệt giữa tính đồng thời (async) và tính song song (isolates) trong Dart. Tôi cũng giải thích rằng dù các thao tác async không bị blocking, chúng vẫn có thể gây ra hiện tượng giật lag giao diện nếu tác vụ quá nặng, vì chúng chạy trên luồng chính. Ngược lại, isolates chạy song song với bộ nhớ và vòng lặp sự kiện riêng, đảm bảo các tác vụ đòi hỏi nhiều tài nguyên không ảnh hưởng đến độ phản hồi của ứng dụng.

Async vs. Isolate trong Flutter: Song song hóa trong Flutter

Có rất nhiều nhầm lẫn giữa khái niệm async và isolates, hay nói cách khác là giữa tính đồng thời (concurrency) và tính song song (parallelism). Hôm nay, trong bài viết này, tôi sẽ giải thích rõ những nhầm lẫn này. Trong bài viết sắp tới, tôi sẽ thực hiện việc triển khai isolates trong Dart, vì vậy hãy theo dõi tôi để không bỏ lỡ các bài viết tiếp theo. Bây giờ, hãy cùng bắt đầu!

ASYNC

void readData() async {
var url = "www.example.com";
var content = await http.get(url); //Async Call
var data = parsingData(content); // Will use isolate here as computation heavy
}

Chương trình sẽ chạy bình thường, sau đó sẽ đợi trong khi một tệp đang được tải xuống. Trong thời gian chờ đợi, các phần khác của chương trình có thể tiếp tục chạy. Tuy nhiên, lưu ý rằng luôn chỉ có một phần của ứng dụng đang chạy tại một thời điểm, bởi vì chúng ta chỉ chạy trên một luồng duy nhất, một bộ xử lý. Async không tự động làm cho ứng dụng của bạn chạy đa luồng. Sau khi tệp được tải xuống, phương thức sẽ tiếp tục thực thi. Đó chính là async. Khi future hoàn tất, nó sẽ tiếp tục từ dòng mã kế tiếp. Phần lớn thời gian, async là tất cả những gì bạn cần.

Trong ví dụ trên, mã của chúng ta sẽ đợi đến dòng thứ hai (await http.get(url)) cho đến khi dữ liệu được tải từ internet và sau đó sẽ phân tích dữ liệu.

Giả sử tệp tin rất lớn và việc phân tích nó đòi hỏi nhiều tài nguyên xử lý. Điều này có làm ứng dụng của chúng ta bị giật không? Bạn có thể nghĩ rằng không, vì việc tính toán diễn ra trong phương thức async, phải không? Nhưng không may, bạn đã sai. Đúng vậy! Việc sử dụng một phương thức async vẫn có thể khiến ứng dụng bị lag hoặc giật.

Bạn có thể thắc mắc tại sao lại như vậy khi việc phân tích dữ liệu diễn ra trong một khối async. Bởi vì, mặc dù phương thức là bất đồng bộ, nhưng có một phần công việc đồng bộ lớn đang diễn ra bên trong nó. Việc phân tích đó là đồng bộ, đang diễn ra trên luồng của bạn. Điều đó sẽ khiến bộ xử lý bận rộn, và không có phần nào khác của ứng dụng sẽ được chạy. Giao diện người dùng sẽ không được làm mới cho đến khi công việc nặng đó hoàn thành, và người dùng sẽ thấy hiện tượng giật.

Vậy giải pháp là gì? Đa luồng với isolates!

ISOLATES

Dart cho phép bạn chạy mã song song qua các isolate. Với một isolate, bạn bắt đầu một chương trình Dart khác, cơ bản là trên một luồng khác, trên một bộ xử lý khác. Hai isolate riêng biệt là hoàn toàn độc lập với nhau. Một isolate sẽ không làm tắc nghẽn isolate khác. Nhờ vậy, ứng dụng của bạn có thể thực hiện các xử lý nặng trong khi vẫn hoạt động mượt mà cho người dùng. Tôi sẽ không đi vào chi tiết cách triển khai các isolate ở đây. Việc đó có phần phức tạp hơn, và bài viết này chỉ nhằm phân biệt giữa hai khái niệm lập trình bất đồng bộ (async) và isolate.

Một isolate giống như một không gian nhỏ trên máy với khối bộ nhớ riêng tư và một luồng duy nhất chạy vòng lặp sự kiện. Trong nhiều ngôn ngữ khác như C++, bạn có thể có nhiều luồng chia sẻ cùng một bộ nhớ và thực hiện bất kỳ mã nào mà chúng muốn. Tuy nhiên, trong Dart, mỗi luồng nằm trong một isolate của riêng nó với bộ nhớ riêng, và nó chỉ xử lý các sự kiện.

Tại sao và khi nào sử dụng Isolates?

Nhiều ứng dụng Dart chạy toàn bộ mã của chúng trong một isolate duy nhất, nhưng bạn có thể có nhiều hơn nếu cần. Nếu bạn có một phép toán cần thực hiện lớn đến mức có thể khiến ứng dụng bị giật khung hình nếu chạy trong isolate chính, bạn có thể sử dụng Isolate.spawn() hoặc hàm compute của Flutter, cả hai đều tạo ra một isolate riêng biệt để xử lý phép toán, để lại isolate chính của bạn tự do để tái xây dựng và hiển thị cây widget trong khi đó. Isolate mới đó sẽ có vòng lặp sự kiện và bộ nhớ riêng, mà isolate gốc, mặc dù là cha của isolate mới này, không được phép truy cập. Đó là nguồn gốc của tên gọi "isolate". Những không gian nhỏ này được giữ tách biệt hoàn toàn với nhau. Thực tế, cách duy nhất để chúng có thể làm việc cùng nhau là bằng cách gửi tin nhắn qua lại. Một isolate sẽ gửi một tin nhắn đến isolate khác, và isolate nhận sẽ xử lý tin nhắn đó bằng vòng lặp sự kiện của nó.

Tổng kết

Async là khả năng chờ đợi các công việc khác mà không làm tắc nghẽn. Async sẽ không tạo ra một luồng riêng biệt cho bạn. Dart sẽ chỉ chuyển đổi giữa các phần khác nhau của chương trình khi cần. Trong hầu hết các trường hợp, điều đó là ổn. Nó giống như khi tôi nói chuyện với bạn và đôi khi kiểm tra điện thoại của mình. Khi tôi kiểm tra điện thoại nhanh chóng, điều đó là ổn — hơi phiền một chút, nhưng không sao. Đúng không? Cuộc trò chuyện của chúng ta vẫn tiếp tục. Nhưng nếu tôi đột nhiên bắt đầu nhìn chằm chằm vào màn hình và bỏ qua bạn thì đó không phải là điều tốt. Đó chính là async. Isolates cho phép bạn chạy các tác vụ song song. Một isolate không quan tâm đến những gì isolate khác đang làm tại bất kỳ thời điểm nào. Cả hai có thể chạy với tốc độ tối đa. Isolates khó thiết lập hơn, nhưng đó cũng là cách duy nhất để xử lý một số tình huống, chẳng hạn như ví dụ về phân tích mà tôi đã đề cập. Isolates giống như khi tôi nói chuyện với bạn và cùng lúc chơi với Dash ở đây. Tôi có thể làm những việc đó song song. Được rồi, hy vọng rằng thông tin này hữu ích.

Isolates đóng vai trò quan trọng trong việc đạt được xử lý đồng thời. Việc thực hiện các thao tác tốn tài nguyên trên luồng chính có thể ảnh hưởng tiêu cực đến hiệu suất của ứng dụng. Khi thời gian có sẵn cho mỗi khung hình giảm với tỷ lệ khung hình cao hơn, các tác vụ vượt quá thời gian có sẵn nên được thực hiện trong các isolate riêng biệt để duy trì việc hiển thị mượt mà.

Mặc dù isolates có một số hạn chế về kích thước dữ liệu truyền tải, việc sử dụng chúng một cách hợp lý có thể nâng cao hiệu suất và hiệu quả của các ứng dụng Flutter một cách đáng kể.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí