Dart Concurrency

Concurrency, atau konkurensi, adalah kemampuan program untuk menjalankan beberapa tugas secara simultan. Ini tidak berarti tugas-tugas itu dijalankan pada waktu yang persis sama, melainkan bahwa program dapat beralih antar tugas dengan cepat, sehingga tampak berjalan bersamaan. Concurrency sangat penting dalam pengembangan aplikasi modern, terutama saat menangani operasi yang memakan waktu lama, seperti pengambilan data dari internet, membaca file dari disk, atau melakukan komputasi berat.

Dart mencapai concurrency melalui konsep Isolates.

Isolates: Otak Terpisah

Bayangkan setiap Isolate 🧠 sebagai “otak” kecil yang terisolasi dari otak-otak lainnya dalam program Anda. Setiap Isolate memiliki memori sendiri dan berjalan di single-threaded event loop yang terpisah. Ini berarti setiap Isolate:

  1. Tidak berbagi memori: Isolasi ini mencegah masalah race condition (di mana dua atau lebih proses mencoba mengakses atau memanipulasi data yang sama secara bersamaan) yang sering terjadi di bahasa pemrograman multi-threaded tradisional.
  2. Berjalan secara independen: Satu Isolate tidak akan memblokir (menghentikan) Isolate lainnya.

Jika kita memiliki tugas yang sangat berat dan memakan waktu lama, seperti komputasi matematika kompleks, menjalankannya di Isolate terpisah akan mencegah aplikasi kita “freeze” atau macet. Aplikasi utama (Isolate utama) akan tetap responsif untuk menangani UI, sementara tugas berat tersebut berjalan di latar belakang.

Cara Berkomunikasi antar Isolates

Karena Isolate tidak berbagi memori, mereka berkomunikasi dengan cara berkirim pesan (message passing). Cara kerjanya seperti ini:

  1. Isolate A (utama) membuat Isolate B (baru).
  2. Isolate B menyelesaikan tugasnya dan mengemas hasilnya ke dalam sebuah pesan.
  3. Isolate B mengirim pesan tersebut kembali ke Isolate A.
  4. Isolate A menerima pesan dan mengambil hasilnya.

Ini mirip seperti kita dan teman yang mengerjakan tugas di ruangan terpisah. Kita tidak bisa langsung mengambil kertas di meja teman kita, tetapi kita bisa melempar pesan melalui jendela untuk bertukar informasi.

Implementasi Dasar dengan Isolate.spawn

Fungsi Isolate.spawn adalah cara paling umum untuk membuat Isolate baru. Fungsi ini menerima dua argumen:

  1. entryPoint: Sebuah fungsi level-atas (atau fungsi statis) yang akan dijalankan di Isolate baru. Fungsi ini akan menjadi “otak” dari Isolate baru.
  2. message: Data yang akan dikirim sebagai argumen ke entryPoint saat Isolate dimulai.

Contoh sederhana: Menghitung bilangan prima yang sangat besar di latar belakang.

import 'dart:io';
import 'dart:isolate';

// Fungsi entry point untuk Isolate baru
void findPrimes(SendPort sendPort) {
  // Komputasi berat: Mencari bilangan prima hingga 100.000
  final primes = <int>[];
  for (int i = 2; i <= 100000; i++) {
    bool isPrime = true;
    for (int j = 2; j <= i / 2; j++) {
      if (i % j == 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) {
      primes.add(i);
    }
  }
  // Kirim hasil kembali ke Isolate utama
  sendPort.send(primes.length);
}

void main() async {
  print('Isolate utama: Mulai mencari bilangan prima...');

  // Membuat ReceivePort untuk menerima pesan dari Isolate baru
  final receivePort = ReceivePort();

  // Memulai Isolate baru dan mengirim SendPort-nya
  await Isolate.spawn(findPrimes, receivePort.sendPort);

  // Menunggu pesan dari Isolate baru
  final result = await receivePort.first;

  print('Isolate utama: Selesai! Ditemukan $result bilangan prima.');
  print('Isolate utama: Program selesai.');
}

Perbedaan Utama: Asynchronous vs. Concurrent

Sangat penting untuk membedakan antara asynchronous dan concurrent di Dart.

  • Asynchronous (Asynchronous Programming): Menggunakan async/await dan Future untuk menangani operasi yang membutuhkan waktu, tetapi tanpa memblokir single-thread utama. Selama operasi Future menunggu, thread utama dapat melakukan tugas lain. Ini ideal untuk I/O (input/output) seperti mengambil data dari internet karena CPU tidak perlu menunggu.
  • Concurrent (Concurrency): Menggunakan Isolates untuk benar-benar menjalankan kode secara paralel di event loop terpisah. Ini ideal untuk tugas yang memakan banyak CPU (CPU-intensive).

Pahami bahwa async/await pada dasarnya adalah asynchronous, bukan concurrent. Jika kita menjalankan komputasi berat di async tanpa Isolate, thread utama tetap akan terblokir. Gunakan Isolate hanya ketika kita memiliki tugas yang benar-benar akan membuat “freeze” aplikasi kita.

Sample source code bisa di download di github pada link berikut dart-tutorial

hyvercode