Isolate & Concurrency

Isolate và Concurrency (đồng thời) là cơ chế trong Dart dùng để thực hiện nhiều công việc mà không làm một công việc phải chờ hoàn thành hoàn toàn mới có thể xử lý công việc khác.

Lý thuyết

1. Concurrency

Concurrency (xử lý đồng thời) là khả năng chương trình quản lý nhiều công việc đang diễn ra trong cùng một khoảng thời gian.

Concurrency không nhất thiết có nghĩa là các công việc chạy chính xác cùng một lúc trên nhiều CPU.

Ví dụ:

Dart có thể bắt đầu Task A, trong lúc A đang chờ I/O thì xử lý Task B.

2. Isolate

Isolate là một đơn vị thực thi độc lập (independent execution unit) trong Dart.

Mỗi Isolate có:

  • Event Loop riêng
  • Memory riêng
  • Call Stack riêng
  • Heap riêng

Các Isolate không chia sẻ trực tiếp memory với nhau.

Do đó, Dart tránh được nhiều vấn đề thường gặp khi nhiều thread cùng truy cập một vùng memory, chẳng hạn race condition.

Cách Isolate hoạt động

Khi một Flutter app chạy:

Flutter App
    │
    ▼
Main Isolate
    │
    ├── UI
    ├── Event Loop
    └── xử lý các tác vụ thông thường

Nếu có một tác vụ CPU-intensive:

Main Isolate
    │
    │ tạo
    ▼
Worker Isolate
    │
    └── xử lý công việc nặng

Hai Isolate không dùng chung memory mà giao tiếp với nhau bằng Message Passing.

Main Isolate
      │
      │ SendPort
      ▼
Worker Isolate
      │
      │ SendPort
      ▼
Main Isolate

Các thành phần chính

  • Isolate: Đơn vị thực thi độc lập của Dart.
  • Main Isolate: Isolate chính, thường chịu trách nhiệm xử lý UI trong Flutter.
  • Worker Isolate: Isolate được tạo để xử lý công việc riêng, đặc biệt là CPU-intensive.
  • Event Loop: Vòng lặp xử lý các event, callback và asynchronous task.
  • SendPort: Dùng để gửi message đến một Isolate khác.
  • ReceivePort: Dùng để nhận message từ Isolate khác.
  • Message Passing: Cơ chế giao tiếp giữa các Isolate.
  • Future/async/await: Xử lý asynchronous trong một Isolate, không tạo Isolate mới.

Concurrency trong Dart

Dart có thể xử lý concurrency theo hai hướng chính:

1. Asynchronous

Sử dụng:

Future
async
await

Thích hợp cho các tác vụ như:

  • API request
  • Database
  • File I/O
  • Network

Ví dụ:

Future<void> fetchData() async {
  print('Bắt đầu');

  await Future.delayed(const Duration(seconds: 2));

  print('Hoàn thành');
}

await làm cho function tạm dừng chờ Future, nhưng không chặn toàn bộ Event Loop.

2. Isolate

Dùng khi cần xử lý CPU-intensive task.

Ví dụ:

import 'dart:isolate';

void calculate(SendPort sendPort) {
  int result = 0;

  for (int i = 0; i < 100000000; i++) {
    result += i;
  }

  sendPort.send(result);
}

Future<void> main() async {
  final receivePort = ReceivePort();

  await Isolate.spawn(
    calculate,
    receivePort.sendPort,
  );

  final result = await receivePort.first;

  print(result);
}

Ở đây:

Isolate.spawn(...)

tạo một Isolate mới.

Worker thực hiện:

calculate()

Sau khi xử lý xong:

sendPort.send(result);

gửi kết quả về Main Isolate.

compute() trong Flutter

Flutter cung cấp:

compute()

để thực hiện một số CPU-intensive task dễ dàng hơn.

import 'package:flutter/foundation.dart';

int calculate(int number) {
  int result = 0;

  for (int i = 0; i < number; i++) {
    result += i;
  }

  return result;
}

Future<void> main() async {
  final result = await compute(calculate, 100000000);

  print(result);
}

compute() giúp đưa công việc sang một Isolate khác thay vì thực hiện trực tiếp trên Main Isolate.

Các khái niệm/từ khóa liên quan

  • Concurrency: Xử lý nhiều công việc đồng thời.
  • Parallelism: Nhiều công việc thực sự chạy song song trên nhiều CPU/core.
  • Isolate: Đơn vị thực thi độc lập của Dart.
  • Thread: Luồng thực thi ở mức hệ điều hành. Isolate không hoàn toàn đồng nghĩa với Thread.
  • Event Loop: Cơ chế xử lý event và asynchronous task.
  • Future: Đại diện cho kết quả sẽ có trong tương lai.
  • async: Đánh dấu function có thể thực hiện asynchronous operation.
  • await: Chờ Future hoàn thành mà không block toàn bộ Event Loop.
  • SendPort: Gửi message.
  • ReceivePort: Nhận message.
  • Message Passing: Các Isolate giao tiếp bằng cách gửi message.

Phân biệt async/await và Isolate

async/await Isolate
Chủ yếu xử lý asynchronous Tạo execution unit riêng
Không tạo Isolate mới Tạo Isolate mới
Phù hợp I/O Phù hợp CPU-intensive
Ví dụ: gọi API Ví dụ: xử lý hàng triệu dữ liệu
Không chia nhỏ memory Mỗi Isolate có memory riêng

Ví dụ:

// I/O → async/await
final response = await fetchData();
// CPU-intensive → Isolate
final result = await compute(calculate, data);

Nguyên tắc cần nhớ

  • I/O-bound → async/await
  • CPU-bound → Isolate
  • Isolate không chia sẻ memory trực tiếp.
  • Các Isolate giao tiếp thông qua message passing.
  • Flutter UI chạy trên Main Isolate.
  • Công việc CPU quá nặng trên Main Isolate có thể làm UI bị giật / dropped frames.
  • async/await không đồng nghĩa với tạo Isolate.
  • Concurrency ≠ Parallelism.

Tóm lại:

  • Concurrency → quản lý nhiều công việc cùng diễn ra.
  • Isolate → đơn vị thực thi độc lập của Dart.
  • Main Isolate → thường xử lý UI và event chính của Flutter.
  • async/await → phù hợp với tác vụ chờ I/O.
  • Isolate / compute() → phù hợp với tác vụ CPU-intensive.
  • Các Isolate không share memory, mà giao tiếp bằng message.
  • Có thể nhớ ngắn gọn: I/O → async/await, CPU nặng → Isolate.

Bài viết khác

Language Switching trong Flutter

        Trong quá trình phát triển ứng dụng di động, khả năng hỗ trợ nhiều ngôn ngữ ngày càng trở nên quan trọng. Một ứng dụng chỉ sử dụng duy nhất một ngôn ngữ có thể gặp khó khăn khi tiếp cận người dùng ở các quốc gia và khu vực khác […]

UTC & Local Time Conversion

Trong thời đại toàn cầu hóa, con người thường xuyên làm việc, học tập và giao tiếp với những người ở các quốc gia khác nhau. Một cuộc họp trực tuyến có thể được tổ chức tại Việt Nam, nhưng người tham gia lại đang ở Hoa Kỳ, Anh, Nhật Bản hoặc Australia. Vì vậy, […]

Logging / Monitoring / CI/CD

1. Logging / Monitoring / CI/CD là gì? Trong quá trình phát triển phần mềm, việc viết code để ứng dụng chạy được chỉ là một phần của công việc. Khi đưa ứng dụng vào sử dụng thực tế, lập trình viên còn phải quan tâm đến nhiều vấn đề khác như ứng dụng có […]

Docker

1. Docker là gì? Docker là một nền tảng được sử dụng để đóng gói, triển khai và chạy ứng dụng trong các môi trường độc lập, được gọi là Container. Docker giúp lập trình viên đưa mã nguồn, thư viện, các gói phụ thuộc và những thành phần cần thiết để chạy ứng dụng […]

Unit Testing và Integration Testing

1. Unit Testing và Integration Testing là gì? Unit Testing và Integration Testing là hai phương pháp kiểm thử phần mềm thường được sử dụng trong quá trình phát triển ứng dụng. Mục đích của hai phương pháp này là kiểm tra xem chương trình có hoạt động đúng theo yêu cầu hay không, đồng […]

Message Broker

1. Message Broker là gì? Message Broker là một thành phần trung gian được sử dụng để tiếp nhận, quản lý và chuyển tiếp thông điệp giữa các ứng dụng hoặc các thành phần trong một hệ thống phần mềm. Công nghệ này thường xuất hiện trong những hệ thống Backend, kiến trúc Microservices và […]

Leave a Reply

Your email address will not be published. Required fields are marked *