Dart Isolates dan Concurrency 2026: compute, Async, dan Pertanyaan Interview
Panduan lengkap tentang Dart isolates, fungsi compute Flutter, dan pola concurrency untuk pengembangan aplikasi yang responsif di tahun 2026.

Dart isolates menyediakan eksekusi paralel sejati dalam aplikasi Flutter, mengatasi keterbatasan single-threaded yang menyebabkan UI lag saat melakukan komputasi berat. Berbeda dengan thread di bahasa pemrograman lain, isolates tidak berbagi memori dan berkomunikasi secara eksklusif melalui message passing, menjadikan kode concurrent lebih aman dan mudah dipahami.
Dart 3.7 memperkenalkan lightweight isolates dengan pengurangan overhead memori hingga 50%. API Isolate.run() kini menangani sebagian besar kasus penggunaan yang sebelumnya memerlukan spawning isolate manual, sementara compute() tetap menjadi pilihan utama untuk workload spesifik Flutter.
Memahami Model Concurrency Dart
Dart mengeksekusi kode dalam event loop single-threaded di setiap isolate. Ini berarti async/await tidak menyediakan paralelisme—hanya memungkinkan operasi I/O non-blocking. Ketika tugas CPU-intensive berjalan di main isolate, UI akan freeze karena event loop tidak dapat memproses frame callbacks.
Solusinya adalah memindahkan pekerjaan berat ke isolate terpisah. Setiap isolate memiliki memory heap dan event loop sendiri, berjalan di thread terpisah yang dikelola oleh Dart VM. Komunikasi terjadi melalui SendPort dan ReceivePort, yang melakukan serialisasi pesan antar isolate.
import 'dart:isolate';
// Komputasi berat yang akan memblokir UI jika dijalankan di main isolate
int computeFibonacci(int n) {
if (n <= 1) return n;
return computeFibonacci(n - 1) + computeFibonacci(n - 2);
}
Future<void> main() async {
// Isolate.run() menangani spawning, message passing, dan cleanup secara otomatis
final result = await Isolate.run(() => computeFibonacci(40));
print('Fibonacci(40) = $result'); // Dikomputasi tanpa memblokir main thread
}Fungsi Isolate.run() yang diperkenalkan di Dart 2.19 menyederhanakan pola umum menjalankan komputasi tunggal di background isolate. Fungsi ini menangani pembuatan port, serialisasi pesan, dan disposal isolate secara otomatis.
Menggunakan compute() dalam Aplikasi Flutter
Flutter menyediakan fungsi compute() yang dirancang khusus untuk memindahkan pekerjaan dari UI isolate. Tidak seperti API isolate mentah, compute() terintegrasi dengan framework Flutter dan menangani boilerplate manajemen isolate.
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:image/image.dart' as img;
// Fungsi top-level diperlukan untuk compute() - tidak boleh closure atau 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, jalankan fungsi, return hasil, dispose isolate
return await compute(_applyGrayscaleFilter, rawImage);
}
}Fungsi yang diberikan ke compute() harus berupa fungsi top-level atau static method. Instance methods dan closures tidak dapat diserialize melintasi batas isolate karena berisi referensi ke objek yang tidak ada di heap isolate target.
Isolate Pools untuk Operasi Berulang
Membuat dan menghancurkan isolate untuk setiap operasi menimbulkan overhead. Untuk tugas yang sering terjadi seperti parsing JSON atau pemrosesan gambar, isolate pool menggunakan kembali worker isolates untuk menghindari biaya spawning yang berulang.
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 ini mempertahankan sejumlah worker isolates yang sudah di-warm-up dan siap menerima tugas. Ketika operasi diminta, pool mendistribusikannya ke worker yang tersedia, menghindari overhead pembuatan isolate baru.
Async/Await vs Isolates: Memilih yang Tepat
Memahami kapan menggunakan async/await versus isolates sangat penting untuk performa aplikasi Flutter. Keduanya menyediakan fitur berbeda dan melayani kasus penggunaan yang berbeda.
import 'dart:convert';
import 'dart:isolate';
import 'package:http/http.dart' as http;
// Async/await: Sempurna untuk I/O operations
Future<String> fetchDataFromApi() async {
// Thread tidak diblokir saat menunggu response HTTP
final response = await http.get(Uri.parse('https://api.example.com/data'));
return response.body;
}
// Isolate: Diperlukan untuk komputasi CPU-intensive
Future<Map<String, dynamic>> parseHugeJson(String jsonString) async {
// JSON parsing besar memblokir event loop - pindahkan ke isolate
return await Isolate.run(() => jsonDecode(jsonString) as Map<String, dynamic>);
}
// Pattern kombinasi untuk operasi real-world
Future<ProcessedData> fetchAndProcessData() async {
// Step 1: Fetch data (I/O bound - gunakan async/await)
final rawJson = await fetchDataFromApi();
// Step 2: Parse JSON besar (CPU bound - gunakan isolate)
final parsed = await parseHugeJson(rawJson);
// Step 3: Transform data (CPU bound - gunakan isolate)
final processed = await Isolate.run(() => transformData(parsed));
return processed;
}
ProcessedData transformData(Map<String, dynamic> data) {
// Transformasi data kompleks
return ProcessedData.fromJson(data);
}
class ProcessedData {
final Map<String, dynamic> data;
ProcessedData(this.data);
factory ProcessedData.fromJson(Map<String, dynamic> json) => ProcessedData(json);
}Gunakan async/await untuk operasi I/O seperti network requests, file reading, dan database queries. Gunakan isolates untuk pekerjaan CPU-intensive seperti image processing, data parsing, dan algoritma kompleks.
Stream Communication antar Isolates
Untuk operasi long-running yang memerlukan progress updates atau multiple results, komunikasi berbasis stream antar isolates sangat diperlukan.
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) {
// Simulasi pemrosesan
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 ini memungkinkan UI menampilkan progress indicators sementara pekerjaan berjalan di background, memberikan feedback kepada pengguna selama operasi yang memakan waktu.
Error Handling dalam Isolates
Error yang terjadi di isolate tidak otomatis propagate ke main isolate. Penanganan error yang tepat sangat penting untuk aplikasi yang robust.
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 menangkap exceptions yang tidak tertangani di isolate dan meneruskannya ke main isolate untuk penanganan yang tepat.
Pertanyaan Interview Umum tentang Dart Concurrency
Berikut adalah pertanyaan interview yang sering ditanyakan beserta jawaban yang diharapkan untuk posisi Flutter developer.
Pertanyaan 1: Apa perbedaan antara async/await dan isolates?
Async/await menyediakan concurrency non-blocking untuk operasi I/O dalam satu isolate. Kode tetap berjalan di thread yang sama, hanya menyerah kontrol saat menunggu Future. Isolates menyediakan true parallelism dengan menjalankan kode di thread terpisah dengan heap memori sendiri.
Pertanyaan 2: Mengapa fungsi yang diberikan ke compute() harus top-level?
Fungsi top-level tidak memiliki referensi ke instance objects atau closures yang tidak dapat diserialize melintasi batas isolate. Isolates tidak berbagi memori, sehingga semua data harus dapat diserialize dan di-copy antar isolate.
Pertanyaan 3: Bagaimana cara berkomunikasi antara main isolate dan background isolate?
Komunikasi menggunakan SendPort dan ReceivePort. Main isolate membuat ReceivePort, mengirim SendPort-nya ke background isolate, dan background isolate menggunakan port tersebut untuk mengirim hasil kembali.
Pertanyaan 4: Kapan sebaiknya menggunakan Isolate.run() vs compute()?
Gunakan compute() dalam konteks Flutter karena terintegrasi dengan framework dan menangani lifecycle dengan benar. Gunakan Isolate.run() untuk aplikasi Dart murni atau ketika lebih banyak kontrol diperlukan.
Siap menguasai wawancara Flutter Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Best Practices untuk Production
Berikut adalah praktik terbaik yang harus diikuti saat mengimplementasikan concurrency dalam aplikasi Flutter production.
Pertama, selalu profile aplikasi sebelum menambahkan isolates. Overhead pembuatan isolate mungkin lebih besar dari manfaatnya untuk operasi kecil. Gunakan DevTools untuk mengidentifikasi bottleneck yang sebenarnya.
Kedua, pertimbangkan batasan memori saat bekerja dengan isolates. Setiap isolate memiliki heap sendiri, dan data yang ditransfer antar isolate di-copy. Transfer data besar berulang kali dapat menyebabkan memory pressure.
Ketiga, gunakan isolate pools untuk operasi berulang. Spawning isolate baru untuk setiap operasi menimbulkan overhead yang signifikan. Pool memungkinkan reuse isolate yang sudah diinisialisasi.
import 'dart:isolate';
import 'package:flutter/foundation.dart';
// Anti-pattern: Membuat isolate untuk operasi kecil
Future<int> badExample(int value) async {
// Overhead isolate lebih besar dari komputasi
return await compute((v) => v * 2, value);
}
// Pattern yang benar: Gunakan isolate untuk batch processing
Future<List<int>> goodExample(List<int> values) async {
// Satu isolate memproses semua items
return await compute((items) => items.map((v) => v * 2).toList(), values);
}
// Pattern terbaik: Gunakan pool untuk operasi berulang
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));
}
}Dengan mengikuti praktik-praktik ini, aplikasi Flutter dapat mencapai performa optimal sambil menjaga responsivitas UI.
Kesimpulan
Dart isolates dan model concurrency menyediakan tools yang powerful untuk membangun aplikasi Flutter yang responsif. Dengan memahami kapan menggunakan async/await untuk I/O operations dan isolates untuk CPU-intensive work, developer dapat menghindari UI jank dan memberikan pengalaman pengguna yang smooth.
Dart 3.7 membuat isolates lebih efisien dengan reduced memory overhead, dan API seperti Isolate.run() dan compute() menyederhanakan pola-pola umum. Untuk interview Flutter, pemahaman mendalam tentang perbedaan antara concurrency dan parallelism, serialization constraints, dan communication patterns sangat penting.
Praktik terbaik termasuk profiling sebelum optimizing, menggunakan isolate pools untuk operasi berulang, dan mempertimbangkan trade-off memori saat mentransfer data besar antar isolates.
Tag
Bagikan
Artikel terkait

Optimasi Performa Flutter pada 2026: Impeller, Rebuild, dan Praktik Terbaik
Cara menjaga aplikasi Flutter pada 60 atau 120 fps yang stabil pada 2026 dengan Impeller, rebuild widget yang disiplin, RepaintBoundary, dan profiling DevTools.

State Management Flutter: Riverpod vs BLoC - Panduan Perbandingan Lengkap
Perbandingan mendalam antara Riverpod dan BLoC untuk state management di Flutter. Arsitektur, performa, kemudahan pengujian, dan kasus penggunaan untuk memilih solusi terbaik.

20 Pertanyaan Wawancara Flutter Teratas untuk Developer Mobile
Persiapkan wawancara Flutter dengan 20 pertanyaan yang paling sering ditanyakan. Widget, state management, Dart, arsitektur, dan praktik terbaik dijelaskan secara detail dengan contoh kode.