Dart Isolates และ Concurrency 2026: compute, Async และคำถามสัมภาษณ์

คู่มือฉบับสมบูรณ์เกี่ยวกับ Dart isolates, ฟังก์ชัน compute ใน Flutter และ pattern ของ concurrency สำหรับการพัฒนาแอปที่ตอบสนองรวดเร็วในปี 2026

Dart Isolates และ Concurrency ใน Flutter 2026

Dart isolates ให้ความสามารถในการประมวลผลแบบขนานอย่างแท้จริงในแอปพลิเคชัน Flutter แก้ปัญหาข้อจำกัดแบบ single-threaded ที่ทำให้ UI กระตุกเมื่อทำการประมวลผลหนัก ต่างจาก threads ในภาษาอื่น isolates ไม่แชร์หน่วยความจำและสื่อสารผ่าน message passing เท่านั้น ทำให้โค้ด concurrent ปลอดภัยและเข้าใจง่ายกว่า

ข้อมูลสำคัญสำหรับปี 2026

Dart 3.7 เปิดตัว lightweight isolates ที่ลด overhead หน่วยความจำลง 50% API Isolate.run() ตอนนี้จัดการกรณีส่วนใหญ่ที่ก่อนหน้านี้ต้อง spawn isolate ด้วยตนเอง ในขณะที่ compute() ยังคงเป็นตัวเลือกหลักสำหรับ workload เฉพาะของ Flutter

ทำความเข้าใจโมเดล Concurrency ของ Dart

Dart ประมวลผลโค้ดใน event loop แบบ single-threaded ภายในแต่ละ isolate ซึ่งหมายความว่า async/await ไม่ได้ให้ parallelism แต่อนุญาตเฉพาะการดำเนินการ I/O แบบ non-blocking เมื่องาน CPU-intensive ทำงานบน main isolate UI จะค้างเพราะ event loop ไม่สามารถประมวลผล frame callbacks ได้

วิธีแก้ไขคือย้ายงานหนักไปยัง isolate แยกต่างหาก แต่ละ isolate มี memory heap และ event loop ของตัวเอง ทำงานบน thread แยกที่จัดการโดย Dart VM การสื่อสารเกิดขึ้นผ่าน SendPort และ ReceivePort ซึ่งทำการ serialize ข้อความระหว่าง isolates

main.dartdart
import 'dart:isolate';

// การประมวลผลหนักที่จะบล็อก UI หากทำงานบน main isolate
int computeFibonacci(int n) {
  if (n <= 1) return n;
  return computeFibonacci(n - 1) + computeFibonacci(n - 2);
}

Future<void> main() async {
  // Isolate.run() จัดการ spawning, message passing และ cleanup โดยอัตโนมัติ
  final result = await Isolate.run(() => computeFibonacci(40));
  print('Fibonacci(40) = $result'); // คำนวณโดยไม่บล็อก main thread
}

ฟังก์ชัน Isolate.run() ที่เปิดตัวใน Dart 2.19 ทำให้ pattern ทั่วไปของการรันการคำนวณเดี่ยวใน background isolate ง่ายขึ้น มันจัดการการสร้าง port, การ serialize ข้อความ และการ dispose isolate โดยอัตโนมัติ

การใช้ compute() ในแอปพลิเคชัน Flutter

Flutter มีฟังก์ชัน compute() ที่ออกแบบมาโดยเฉพาะสำหรับการย้ายงานออกจาก UI isolate ต่างจาก API isolate แบบดิบ compute() ทำงานร่วมกับ framework ของ Flutter และจัดการ boilerplate ของการจัดการ isolate

image_processor.dartdart
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:image/image.dart' as img;

// ฟังก์ชัน top-level จำเป็นสำหรับ compute() - ไม่สามารถเป็น closure หรือ method ได้
Uint8List _applyGrayscaleFilter(Uint8List imageBytes) {
  final image = img.decodeImage(imageBytes)!;
  final grayscale = img.grayscale(image);
  return Uint8List.fromList(img.encodePng(grayscale));
}

class ImageProcessor {
  Future<Uint8List> processImage(Uint8List rawImage) async {
    // compute() spawn isolate, รันฟังก์ชัน, คืนค่าผลลัพธ์, dispose isolate
    return await compute(_applyGrayscaleFilter, rawImage);
  }
}

ฟังก์ชันที่ส่งไปยัง compute() ต้องเป็นฟังก์ชัน top-level หรือ static method Instance methods และ closures ไม่สามารถ serialize ข้ามขอบเขต isolate ได้เพราะมีการอ้างอิงถึง objects ที่ไม่มีอยู่ใน heap ของ isolate เป้าหมาย

Isolate Pools สำหรับการดำเนินการซ้ำๆ

การสร้างและทำลาย isolate สำหรับแต่ละการดำเนินการทำให้เกิด overhead สำหรับงานที่เกิดขึ้นบ่อยเช่นการ parse JSON หรือการประมวลผลรูปภาพ isolate pool จะใช้ worker isolates ซ้ำเพื่อหลีกเลี่ยงค่าใช้จ่ายในการ spawn ซ้ำๆ

isolate_pool.dartdart
import 'dart:async';
import 'dart:isolate';

class IsolatePool {
  final int size;
  final List<Isolate> _isolates = [];
  final List<SendPort> _sendPorts = [];
  final List<Completer<SendPort>> _available = [];
  bool _initialized = false;

  IsolatePool({this.size = 4});

  Future<void> initialize() async {
    if (_initialized) return;
    
    for (int i = 0; i < size; i++) {
      final receivePort = ReceivePort();
      final isolate = await Isolate.spawn(_workerEntryPoint, receivePort.sendPort);
      _isolates.add(isolate);
      
      final sendPort = await receivePort.first as SendPort;
      _sendPorts.add(sendPort);
      _available.add(Completer()..complete(sendPort));
    }
    _initialized = true;
  }

  static void _workerEntryPoint(SendPort mainSendPort) {
    final receivePort = ReceivePort();
    mainSendPort.send(receivePort.sendPort);
    
    receivePort.listen((message) {
      final data = message as Map<String, dynamic>;
      final function = data['function'] as Function;
      final argument = data['argument'];
      final replyPort = data['replyPort'] as SendPort;
      
      final result = function(argument);
      replyPort.send(result);
    });
  }

  Future<R> execute<T, R>(R Function(T) function, T argument) async {
    await initialize();
    final completer = _available.removeAt(0);
    final sendPort = await completer.future;
    
    final responsePort = ReceivePort();
    sendPort.send({
      'function': function,
      'argument': argument,
      'replyPort': responsePort.sendPort,
    });
    
    final result = await responsePort.first as R;
    _available.add(Completer()..complete(sendPort));
    return result;
  }

  void dispose() {
    for (final isolate in _isolates) {
      isolate.kill();
    }
    _isolates.clear();
    _sendPorts.clear();
  }
}

Pool นี้รักษาจำนวน worker isolates ที่ warm up ไว้แล้วและพร้อมรับงาน เมื่อมีการร้องขอการดำเนินการ pool จะแจกจ่ายไปยัง worker ที่ว่างอยู่ หลีกเลี่ยง overhead ของการสร้าง isolate ใหม่

Async/Await vs Isolates: เลือกอย่างถูกต้อง

การเข้าใจว่าเมื่อไหร่ควรใช้ async/await เทียบกับ isolates เป็นสิ่งสำคัญสำหรับประสิทธิภาพของแอปพลิเคชัน Flutter ทั้งสองให้ความสามารถที่แตกต่างกันและรองรับกรณีการใช้งานที่แตกต่างกัน

async_vs_isolates.dartdart
import 'dart:convert';
import 'dart:isolate';
import 'package:http/http.dart' as http;

// Async/await: เหมาะสำหรับ I/O operations
Future<String> fetchDataFromApi() async {
  // Thread ไม่ถูกบล็อกขณะรอ response HTTP
  final response = await http.get(Uri.parse('https://api.example.com/data'));
  return response.body;
}

// Isolate: จำเป็นสำหรับการคำนวณ CPU-intensive
Future<Map<String, dynamic>> parseHugeJson(String jsonString) async {
  // การ parse JSON ขนาดใหญ่บล็อก event loop - ย้ายไป isolate
  return await Isolate.run(() => jsonDecode(jsonString) as Map<String, dynamic>);
}

// Pattern รวมสำหรับการดำเนินการจริง
Future<ProcessedData> fetchAndProcessData() async {
  // ขั้นตอน 1: Fetch data (I/O bound - ใช้ async/await)
  final rawJson = await fetchDataFromApi();
  
  // ขั้นตอน 2: Parse JSON ขนาดใหญ่ (CPU bound - ใช้ isolate)
  final parsed = await parseHugeJson(rawJson);
  
  // ขั้นตอน 3: Transform data (CPU bound - ใช้ isolate)
  final processed = await Isolate.run(() => transformData(parsed));
  
  return processed;
}

ProcessedData transformData(Map<String, dynamic> data) {
  // การแปลงข้อมูลที่ซับซ้อน
  return ProcessedData.fromJson(data);
}

class ProcessedData {
  final Map<String, dynamic> data;
  ProcessedData(this.data);
  factory ProcessedData.fromJson(Map<String, dynamic> json) => ProcessedData(json);
}

ใช้ async/await สำหรับการดำเนินการ I/O เช่น network requests, การอ่านไฟล์ และ database queries ใช้ isolates สำหรับงาน CPU-intensive เช่นการประมวลผลรูปภาพ, การ parse ข้อมูล และ algorithms ที่ซับซ้อน

Stream Communication ระหว่าง Isolates

สำหรับการดำเนินการที่ใช้เวลานานที่ต้องการการอัปเดตความคืบหน้าหรือผลลัพธ์หลายรายการ การสื่อสารแบบ stream ระหว่าง isolates เป็นสิ่งจำเป็น

stream_isolate.dartdart
import 'dart:async';
import 'dart:isolate';

class ProgressIsolate {
  static Stream<ProgressUpdate> processWithProgress(List<int> items) async* {
    final receivePort = ReceivePort();
    
    await Isolate.spawn(
      _processItems,
      _ProcessRequest(items, receivePort.sendPort),
    );
    
    await for (final message in receivePort) {
      if (message is ProgressUpdate) {
        yield message;
      } else if (message == 'done') {
        break;
      }
    }
  }
  
  static void _processItems(_ProcessRequest request) {
    final total = request.items.length;
    var processed = 0;
    
    for (final item in request.items) {
      // จำลองการประมวลผล
      final result = item * 2;
      processed++;
      
      request.sendPort.send(ProgressUpdate(
        current: processed,
        total: total,
        result: result,
      ));
    }
    
    request.sendPort.send('done');
  }
}

class _ProcessRequest {
  final List<int> items;
  final SendPort sendPort;
  _ProcessRequest(this.items, this.sendPort);
}

class ProgressUpdate {
  final int current;
  final int total;
  final int result;
  
  ProgressUpdate({
    required this.current,
    required this.total,
    required this.result,
  });
  
  double get percentage => current / total;
}

Pattern นี้ช่วยให้ UI แสดง progress indicators ในขณะที่งานทำงานอยู่ใน background ให้ feedback แก่ผู้ใช้ระหว่างการดำเนินการที่ใช้เวลานาน

การจัดการ Error ใน Isolates

Error ที่เกิดขึ้นใน isolate จะไม่ propagate ไปยัง main isolate โดยอัตโนมัติ การจัดการ error ที่เหมาะสมเป็นสิ่งสำคัญสำหรับแอปพลิเคชันที่ robust

error_handling.dartdart
import 'dart:async';
import 'dart:isolate';

class IsolateErrorHandler {
  static Future<T> runWithErrorHandling<T>(
    T Function() computation,
  ) async {
    final receivePort = ReceivePort();
    final errorPort = ReceivePort();
    
    final isolate = await Isolate.spawn(
      _runComputation<T>,
      _ComputationRequest<T>(computation, receivePort.sendPort),
      onError: errorPort.sendPort,
    );
    
    final completer = Completer<T>();
    
    receivePort.listen((message) {
      if (!completer.isCompleted) {
        completer.complete(message as T);
      }
      receivePort.close();
      errorPort.close();
      isolate.kill();
    });
    
    errorPort.listen((error) {
      if (!completer.isCompleted) {
        final errorList = error as List;
        completer.completeError(
          IsolateException(errorList[0].toString()),
          StackTrace.fromString(errorList[1].toString()),
        );
      }
      receivePort.close();
      errorPort.close();
      isolate.kill();
    });
    
    return completer.future;
  }
  
  static void _runComputation<T>(_ComputationRequest<T> request) {
    final result = request.computation();
    request.sendPort.send(result);
  }
}

class _ComputationRequest<T> {
  final T Function() computation;
  final SendPort sendPort;
  _ComputationRequest(this.computation, this.sendPort);
}

class IsolateException implements Exception {
  final String message;
  IsolateException(this.message);
  
  
  String toString() => 'IsolateException: $message';
}

Error port จับ exceptions ที่ไม่ได้รับการจัดการใน isolate และส่งต่อไปยัง main isolate เพื่อการจัดการที่เหมาะสม

คำถามสัมภาษณ์ทั่วไปเกี่ยวกับ Dart Concurrency

ต่อไปนี้คือคำถามสัมภาษณ์ที่พบบ่อยพร้อมคำตอบที่คาดหวังสำหรับตำแหน่ง Flutter developer

คำถาม 1: ความแตกต่างระหว่าง async/await และ isolates คืออะไร?

Async/await ให้ concurrency แบบ non-blocking สำหรับการดำเนินการ I/O ภายใน isolate เดียว โค้ดยังคงทำงานบน thread เดียวกัน เพียงแค่ yield control เมื่อรอ Future Isolates ให้ true parallelism โดยการรันโค้ดบน thread แยกพร้อม memory heap ของตัวเอง

คำถาม 2: ทำไมฟังก์ชันที่ส่งให้ compute() ต้องเป็น top-level?

ฟังก์ชัน top-level ไม่มีการอ้างอิงถึง instance objects หรือ closures ที่ไม่สามารถ serialize ข้ามขอบเขต isolate ได้ Isolates ไม่แชร์หน่วยความจำ ดังนั้นข้อมูลทั้งหมดต้องสามารถ serialize และคัดลอกระหว่าง isolates ได้

คำถาม 3: การสื่อสารระหว่าง main isolate และ background isolate ทำอย่างไร?

การสื่อสารใช้ SendPort และ ReceivePort Main isolate สร้าง ReceivePort ส่ง SendPort ไปยัง background isolate และ background isolate ใช้ port นั้นในการส่งผลลัพธ์กลับ

คำถาม 4: เมื่อไหร่ควรใช้ Isolate.run() vs compute()?

ใช้ compute() ในบริบท Flutter เพราะมันทำงานร่วมกับ framework และจัดการ lifecycle อย่างถูกต้อง ใช้ Isolate.run() สำหรับแอปพลิเคชัน Dart ล้วนหรือเมื่อต้องการควบคุมมากขึ้น

พร้อมที่จะพิชิตการสัมภาษณ์ Flutter แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

Best Practices สำหรับ Production

ต่อไปนี้คือแนวทางปฏิบัติที่ดีที่สุดที่ควรปฏิบัติตามเมื่อ implement concurrency ในแอปพลิเคชัน Flutter production

ประการแรก ควร profile แอปพลิเคชันก่อนเพิ่ม isolates เสมอ Overhead ของการสร้าง isolate อาจมากกว่าประโยชน์สำหรับการดำเนินการขนาดเล็ก ใช้ DevTools เพื่อระบุ bottleneck ที่แท้จริง

ประการที่สอง พิจารณาข้อจำกัดของหน่วยความจำเมื่อทำงานกับ isolates แต่ละ isolate มี heap ของตัวเอง และข้อมูลที่ถ่ายโอนระหว่าง isolates จะถูกคัดลอก การถ่ายโอนข้อมูลขนาดใหญ่ซ้ำๆ อาจทำให้เกิด memory pressure

ประการที่สาม ใช้ isolate pools สำหรับการดำเนินการซ้ำๆ การ spawn isolate ใหม่สำหรับแต่ละการดำเนินการทำให้เกิด overhead ที่มาก Pool ช่วยให้สามารถใช้ isolate ที่เริ่มต้นแล้วซ้ำได้

best_practices.dartdart
import 'dart:isolate';
import 'package:flutter/foundation.dart';

// Anti-pattern: สร้าง isolate สำหรับการดำเนินการขนาดเล็ก
Future<int> badExample(int value) async {
  // Overhead ของ isolate มากกว่าการคำนวณ
  return await compute((v) => v * 2, value);
}

// Pattern ที่ถูกต้อง: ใช้ isolate สำหรับ batch processing
Future<List<int>> goodExample(List<int> values) async {
  // isolate เดียวประมวลผลทุก items
  return await compute((items) => items.map((v) => v * 2).toList(), values);
}

// Pattern ที่ดีที่สุด: ใช้ pool สำหรับการดำเนินการซ้ำๆ
class ProcessingService {
  static final IsolatePool _pool = IsolatePool(size: 4);
  
  Future<List<int>> processItems(List<int> items) async {
    return await _pool.execute(
      (data) => data.map((v) => v * 2).toList(),
      items,
    );
  }
}

class IsolatePool {
  final int size;
  IsolatePool({required this.size});
  
  Future<R> execute<T, R>(R Function(T) fn, T arg) async {
    return await Isolate.run(() => fn(arg));
  }
}

โดยการปฏิบัติตามแนวทางเหล่านี้ แอปพลิเคชัน Flutter สามารถบรรลุประสิทธิภาพที่เหมาะสมในขณะที่รักษา UI ให้ตอบสนองรวดเร็ว

สรุป

Dart isolates และโมเดล concurrency มอบเครื่องมือที่ทรงพลังสำหรับการสร้างแอปพลิเคชัน Flutter ที่ตอบสนองรวดเร็ว โดยการเข้าใจว่าเมื่อไหร่ควรใช้ async/await สำหรับการดำเนินการ I/O และ isolates สำหรับงาน CPU-intensive นักพัฒนาสามารถหลีกเลี่ยง UI jank และมอบประสบการณ์ผู้ใช้ที่ลื่นไหล

Dart 3.7 ทำให้ isolates มีประสิทธิภาพมากขึ้นด้วยการลด overhead หน่วยความจำ และ APIs เช่น Isolate.run() และ compute() ทำให้ patterns ทั่วไปง่ายขึ้น สำหรับการสัมภาษณ์ Flutter ความเข้าใจอย่างลึกซึ้งเกี่ยวกับความแตกต่างระหว่าง concurrency และ parallelism, serialization constraints และ communication patterns เป็นสิ่งสำคัญ

แนวทางปฏิบัติที่ดีที่สุดรวมถึงการ profiling ก่อน optimizing, การใช้ isolate pools สำหรับการดำเนินการซ้ำๆ และการพิจารณา trade-off ของหน่วยความจำเมื่อถ่ายโอนข้อมูลขนาดใหญ่ระหว่าง isolates

แท็ก

#flutter
#dart
#concurrency
#isolates
#performance

แชร์

บทความที่เกี่ยวข้อง

การเพิ่มประสิทธิภาพ Flutter ด้วย Impeller และการลดการรีบิลด์วิดเจ็ต

การเพิ่มประสิทธิภาพ Flutter ในปี 2026: Impeller, การรีบิลด์ และแนวปฏิบัติที่ดี

วิธีคงแอป Flutter ไว้ที่ 60 หรือ 120fps อย่างคงที่ในปี 2026 ด้วย Impeller, การรีบิลด์วิดเจ็ตอย่างมีวินัย, RepaintBoundary และการ profiling ด้วย DevTools

การเปรียบเทียบ Riverpod และ BLoC สำหรับการจัดการ state ใน Flutter

การจัดการ State ใน Flutter: Riverpod vs BLoC - คู่มือเปรียบเทียบฉบับสมบูรณ์

การเปรียบเทียบเชิงลึกระหว่าง Riverpod และ BLoC สำหรับการจัดการ state ใน Flutter สถาปัตยกรรม ประสิทธิภาพ ความสามารถในการทดสอบ และกรณีการใช้งานเพื่อเลือกโซลูชันที่ดีที่สุด

คำถามสัมภาษณ์งาน Flutter สำหรับนักพัฒนาแอปมือถือ

20 คำถามสัมภาษณ์งาน Flutter ที่พบบ่อยที่สุดสำหรับนักพัฒนาแอปมือถือ

เตรียมตัวสัมภาษณ์งาน Flutter ด้วยคำถาม 20 ข้อที่ถูกถามบ่อยที่สุด ครอบคลุม Widget, State Management, Dart, สถาปัตยกรรม และแนวทางปฏิบัติที่ดีที่สุด พร้อมคำอธิบายอย่างละเอียดและตัวอย่างโค้ด