Skip to Content
Flutter⚡ Nâng cao🧵 Isolates & Đa luồng

Isolates và Đa luồng trong Dart/Flutter

Dart là ngôn ngữ single-threaded nhưng vẫn có thể xử lý concurrent tasks thông qua Isolates. Hiểu về Isolates giúp bạn xây dựng ứng dụng Flutter mượt mà với các tác vụ nặng.


1. Dart Single-Threaded Model

┌─────────────────────────────────────────────────────────────────────┐ │ DART EXECUTION MODEL │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Dart code chạy trong MỘT thread duy nhất (Main Isolate) │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ MAIN ISOLATE │ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ │ │ EVENT LOOP │ │ │ │ │ │ │ │ │ │ │ │ ┌───────────┐ ┌───────────┐ │ │ │ │ │ │ │ Microtask │ ───▶ │ Event │ │ │ │ │ │ │ │ Queue │ │ Queue │ │ │ │ │ │ │ └───────────┘ └───────────┘ │ │ │ │ │ │ ↑ ↑ │ │ │ │ │ │ Futures, UI events, │ │ │ │ │ │ async/await I/O callbacks, │ │ │ │ │ │ Timer callbacks │ │ │ │ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ Single-threaded = Tất cả code Dart chạy lần lượt, không song song │ │ │ └─────────────────────────────────────────────────────────────────────┘

2. Vấn đề với Single Thread

┌─────────────────────────────────────────────────────────────────────┐ │ BLOCKING THE UI THREAD │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ❌ Khi chạy tác vụ nặng trên Main Isolate: │ │ │ │ Frame 1 Frame 2 Frame 3 Frame 4 Frame 5 │ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │ Paint │ │ Paint │ │ │ │ │ │ Paint │ │ │ └───────┘ └───────┘ │ HEAVY │ │ TASK │ └───────┘ │ │ │ TASK │ │ ... │ │ │ OK OK │ ... │ │ │ OK │ │ └───────┘ └───────┘ │ │ ↑ │ │ JANK! │ │ UI bị đóng băng │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Các tác vụ nặng: │ │ │ │ • JSON parsing lớn │ │ │ │ • Image processing │ │ │ │ • Encryption/Decryption │ │ │ │ • Complex calculations │ │ │ │ • File compression │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘

3. Isolate là gì?

Isolate là một execution context độc lập với:

  • Riêng memory heap
  • Riêng event loop
  • Không chia sẻ state với các Isolates khác
┌─────────────────────────────────────────────────────────────────────┐ │ ISOLATES │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ MAIN ISOLATE │ │ WORKER ISOLATE │ │ │ │ │ │ │ │ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │ │ │ │ Memory │ │ │ │ Memory │ │ │ │ │ │ Heap │ │ │ │ Heap │ │ │ │ │ └───────────────┘ │ │ └───────────────┘ │ │ │ │ │ │ │ │ │ │ ┌───────────────┐ │ │ ┌───────────────┐ │ │ │ │ │ Event Loop │ │ │ │ Event Loop │ │ │ │ │ └───────────────┘ │ │ └───────────────┘ │ │ │ │ │ │ │ │ │ └──────────┬──────────┘ └──────────┬──────────┘ │ │ │ │ │ │ │ MESSAGES │ │ │ └─────────────⇄─────────────┘ │ │ (SendPort/ReceivePort) │ │ │ │ ⚠️ Không thể chia sẻ objects trực tiếp │ │ ⚠️ Giao tiếp qua message passing │ │ │ └─────────────────────────────────────────────────────────────────────┘

4. Isolate vs Thread

┌─────────────────────────────────────────────────────────────────────┐ │ ISOLATE vs THREAD │ ├────────────────────────────┬────────────────────────────────────────┤ │ THREAD │ ISOLATE │ ├────────────────────────────┼────────────────────────────────────────┤ │ │ │ │ Shared memory │ Separate memory │ │ ┌────────┐ ┌────────┐ │ ┌────────┐ ┌────────┐ │ │ │Thread 1│ │Thread 2│ │ │Isolate1│ │Isolate2│ │ │ └───┬────┘ └───┬────┘ │ └────────┘ └────────┘ │ │ │ │ │ │ │ │ │ └────┬─────┘ │ │ │ │ │ ▼ │ ▼ ▼ │ │ ┌────────┐ │ ┌────────┐ ┌────────┐ │ │ │ Shared │ │ │ Memory │ │ Memory │ │ │ │ Memory │ │ │ A │ │ B │ │ │ └────────┘ │ └────────┘ └────────┘ │ │ │ │ │ → Race conditions! │ → No race conditions! │ │ → Locks needed │ → No locks needed │ │ → Deadlock possible │ → Message passing │ │ │ │ └────────────────────────────┴────────────────────────────────────────┘

5. Cách sử dụng Isolates

5.1 Compute (Simple)

Cho tác vụ đơn giản, dùng compute():

// Heavy function (chạy trong isolate khác) int heavyComputation(int value) { var result = 0; for (var i = 0; i < value * 1000000; i++) { result += i; } return result; } // Gọi từ UI void processData() async { // Chạy trong isolate riêng, UI không bị block final result = await compute(heavyComputation, 1000); print('Result: $result'); }

5.2 Isolate.run (Dart 2.19+)

void processData() async { final result = await Isolate.run(() { // Code này chạy trong isolate khác return heavyComputation(1000); }); print('Result: $result'); }

5.3 Long-running Isolate (Manual)

// Cho tác vụ phức tạp, cần giao tiếp liên tục late Isolate _isolate; late ReceivePort _receivePort; late SendPort _sendPort; void startWorker() async { _receivePort = ReceivePort(); _isolate = await Isolate.spawn(workerFunction, _receivePort.sendPort); // Nhận SendPort từ worker _sendPort = await _receivePort.first as SendPort; } static void workerFunction(SendPort mainSendPort) { final workerReceivePort = ReceivePort(); mainSendPort.send(workerReceivePort.sendPort); workerReceivePort.listen((message) { // Xử lý message từ main final result = heavyComputation(message); mainSendPort.send(result); }); }

6. Message Passing

┌─────────────────────────────────────────────────────────────────────┐ │ MESSAGE PASSING │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ MAIN ISOLATE │ │ WORKER ISOLATE │ │ │ │ │ │ │ │ │ │ SendPort ─────────────────▶ ReceivePort │ │ │ │ (send messages) │ │ (receive messages) │ │ │ │ │ │ │ │ │ │ ReceivePort ◀───────────── SendPort │ │ │ │ (receive results) │ │ (send results) │ │ │ │ │ │ │ │ │ └─────────────────────┘ └─────────────────────┘ │ │ │ │ ⚠️ Messages được COPY, không phải shared reference │ │ │ │ Có thể gửi: │ │ ├── Primitive types (int, double, String, bool) │ │ ├── Lists và Maps (với primitive values) │ │ ├── SendPort/ReceivePort │ │ ├── TypedData (Uint8List, etc.) │ │ └── TransferableTypedData (zero-copy transfer) │ │ │ │ Không thể gửi: │ │ ├── Closures │ │ ├── Objects với state phức tạp │ │ └── UI widgets, BuildContext │ │ │ └─────────────────────────────────────────────────────────────────────┘

7. Khi nào dùng Isolate?

┌─────────────────────────────────────────────────────────────────────┐ │ DECISION TREE │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Tác vụ mất bao lâu? │ │ │ │ │ ┌───────────┴───────────┐ │ │ │ │ │ │ < 16ms > 16ms │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────────────┐ │ │ │ Main Isolate │ │ Cần Isolate riêng? │ │ │ │ OK! │ │ │ │ │ └──────────────┘ └──────────┬───────────┘ │ │ │ │ │ ┌──────────────┴──────────────┐ │ │ │ │ │ │ One-time Long-running │ │ calculation worker │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ compute() or │ │ Isolate.spawn│ │ │ │ Isolate.run()│ │ with ports │ │ │ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘

8. Isolate trong Flutter

┌─────────────────────────────────────────────────────────────────────┐ │ FLUTTER THREADING MODEL │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ MAIN ISOLATE (UI Thread) │ │ │ │ │ │ │ │ ├── Widget building │ │ │ │ ├── Layout │ │ │ │ ├── Paint │ │ │ │ ├── Event handling │ │ │ │ └── Flutter framework code │ │ │ │ │ │ │ │ ⚠️ KHÔNG được block thread này! │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ ENGINE THREADS (Native) │ │ │ │ │ │ │ │ ├── Raster Thread (GPU rendering) │ │ │ │ ├── IO Thread (asset loading, image decoding) │ │ │ │ └── Platform Thread (native channels) │ │ │ │ │ │ │ │ ✓ Managed by Flutter, không cần developer can thiệp │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ USER ISOLATES (Optional) │ │ │ │ │ │ │ │ ├── JSON parsing │ │ │ │ ├── Image processing │ │ │ │ ├── Encryption │ │ │ │ ├── Database operations │ │ │ │ └── Complex calculations │ │ │ │ │ │ │ │ ✓ Developer tạo khi cần │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘

9. Practical Examples

JSON Parsing

// ❌ Bad: Parse JSON trên main isolate final data = jsonDecode(largeJsonString); // ✅ Good: Parse trong isolate riêng final data = await compute(jsonDecode, largeJsonString);

Image Processing

// Heavy image processing Future<Uint8List> processImage(Uint8List imageBytes) async { return await compute(_doProcessing, imageBytes); } Uint8List _doProcessing(Uint8List bytes) { // Apply filters, resize, etc. // Runs in separate isolate return processedBytes; }

📝 Tóm tắt

ConceptDescription
Single-threadedDart code chạy trên 1 thread duy nhất
Event LoopXử lý events và microtasks lần lượt
IsolateExecution context riêng biệt
Message PassingCách giao tiếp giữa Isolates
Use CaseSolution
Quick one-time taskcompute() or Isolate.run()
Long-running workerIsolate.spawn() with ports
Simple asyncasync/await (no isolate needed)

Quy tắc vàng:

Nếu tác vụ mất hơn 16ms (1 frame @ 60fps), hãy cân nhắc dùng Isolate để tránh jank UI.

Last updated on