Dart: Dart Isolates

Última atualização: 2026-08-26

Isolate é a forma do Dart fazer paralelismo — sem memória compartilhada, naturalmente livre de race conditions, seguro e eficiente.

1. O que Você Aprenderá


2. A História Real de um Desenvolvedor

(1) A Dor: Processamento de Um Milhão de Registros Muito Lento em Uma Única Thread

O DataPipeline do Bob precisava realizar análises estatísticas sobre 1.200.000 pedidos. O processamento em thread única levava 15 segundos, mas os clientes SaaS exigiam que o relatório fosse gerado em até 5 segundos. Bob tentou multithreading, mas os bloqueios de memória compartilhada e as race conditions o levaram a gastar uma semana corrigindo bugs de concorrência antes de finalmente desistir. O relatório ainda levava 15 segundos.

(2) A Solução com Isolates

Os Isolates do Dart são unidades paralelas sem memória compartilhada. Cada Isolate possui sua própria memória heap independente e se comunica via passagem de mensagens. Sem memória compartilhada significa sem race conditions.

DART
// Dividir 1,2M pedidos em 4 Isolates, cada um processa 300K
final results = await Future.wait([
  Isolate.run(() => processChunk(orders.sublist(0, 300000))),
  Isolate.run(() => processChunk(orders.sublist(300000, 600000))),
  Isolate.run(() => processChunk(orders.sublist(600000, 900000))),
  Isolate.run(() => processChunk(orders.sublist(900000, 1200000))),
]);
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

(3) Os Benefícios


3. Fundamentos de Isolate

(1) Isolate vs Thread

100%
flowchart TD
  A[Main Isolate] -->|"SendPort"| B[Worker Isolate 1]
  A -->|"SendPort"| C[Worker Isolate 2]
  A -->|"SendPort"| D[Worker Isolate N]
  B -->|"SendPort"| A
  C -->|"SendPort"| A
  D -->|"SendPort"| A
  subgraph Data Sharding
    B -- 300K pedidos
    C -- 300K pedidos
    D -- 400K pedidos
  end
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.
Dimensão Thread (Java/C++) Isolate (Dart)
Memória Compartilhada Independente
Comunicação Variáveis compartilhadas + Locks Passagem de Mensagens
Race Conditions Sim Não
Sincronização de Dados Bloqueio manual necessário Nenhum lock necessário
Custo de Criação Baixo Médio (dados devem ser copiados)

4. Isolate.run — Uma Tarefa Única Simplificada

(1) O Uso Mais Simples de Isolate

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Básico do Isolate.run

DART
import 'dart:isolate';

// Computação custosa para rodar em isolate
int fibonacci(int n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

Future<void> main() async {
  print('Computando fibonacci(40) em isolate...');

  final result = await Isolate.run(() => fibonacci(40));

  print('Resultado: $result');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Processamento de Pedaços de Dados com Isolate.run

DART
import 'dart:isolate';

// Processar um pedaço de pedidos
double processChunk(List<Map<String, dynamic>> orders) {
  double total = 0;
  for (final order in orders) {
    total += (order['amount'] as double);
  }
  return total;
}

Future<void> main() async {
  // Simular 1M pedidos
  final orders = List.generate(
    1000000,
    (i) => {'id': 'ORD-$i', 'amount': (i % 100 + 1) * 10.0},
  );

  // Dividir em 4 pedaços
  final chunkSize = orders.length ~/ 4;
  final chunks = List.generate(
    4,
    (i) => orders.sublist(i * chunkSize, (i + 1) * chunkSize),
  );

  // Processar pedaços em paralelo
  final stopwatch = Stopwatch()..start();
  final results = await Future.wait(
    chunks.map((chunk) => Isolate.run(() => processChunk(chunk))),
  );
  stopwatch.stop();

  final totalRevenue = results.fold(0.0, (a, b) => a + b);
  print('Receita total: \$${totalRevenue.toStringAsFixed(2)} USD');
  print('Tempo: ${stopwatch.elapsedMilliseconds}ms');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

5. Isolate.spawn e Comunicação Bidirecional

(1) Comunicação SendPort / ReceivePort

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Comunicação Bidirecional

DART
import 'dart:isolate';

// Função worker - roda em isolate separado
void workerIsolate(SendPort mainSendPort) {
  final workerReceivePort = ReceivePort();

  // Enviar nossa porta de recebimento para o isolate principal
  mainSendPort.send(workerReceivePort.sendPort);

  // Ouvir mensagens do isolate principal
  workerReceivePort.listen((message) {
    if (message is String && message == 'shutdown') {
      workerReceivePort.close();
      return;
    }

    // Processar dados e enviar resultado de volta
    if (message is List<double>) {
      final total = message.fold(0.0, (a, b) => a + b);
      mainSendPort.send(total);
    }
  });
}

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

  // Criar worker isolate
  await Isolate.spawn(workerIsolate, mainReceivePort.sendPort);

  // Obter porta de envio do worker
  final workerSendPort = await mainReceivePort.first as SendPort;

  // Criar uma nova porta de recebimento para resposta
  final responsePort = ReceivePort();
  workerSendPort.send([1500.0, 3200.0, 890.0]);

  // Aguardar resposta
  final result = await responsePort.first;
  print('Resultado do worker: $result');

  // Desligar worker
  workerSendPort.send('shutdown');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependente da versão do SDK.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

: Comunicação Multi-turno

DART
import 'dart:isolate';

void dataWorker(SendPort mainPort) {
  final receivePort = ReceivePort();
  mainPort.send(receivePort.sendPort);

  receivePort.listen((message) {
    if (message == 'done') {
      receivePort.close();
      return;
    }

    if (message is Map<String, dynamic>) {
      // Processar dados de pedido
      final amount = message['amount'] as double;
      final taxRate = message['taxRate'] as double? ?? 0.08;
      final total = amount * (1 + taxRate);
      mainPort.send({'id': message['id'], 'total': total});
    }
  });
}

Future<void> main() async {
  final mainPort = ReceivePort();
  await Isolate.spawn(dataWorker, mainPort.sendPort);

  final workerPort = await mainPort.first as SendPort;

  // Enviar múltiplas mensagens
  final responsePort = ReceivePort();
  workerPort.add({'id': 'ORD-001', 'amount': 1500.0, 'taxRate': 0.08});
  workerPort.add({'id': 'ORD-002', 'amount': 3200.0});

  // ... comunicação simplificada
  workerPort.send('done');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

6. Isolates e Transferência de Dados

(1) Regras de Transferência de Dados

Método de Transferência Descrição Desempenho
Tipos Primitivos int/double/String/bool Cópia rápida
List/Map Cópia profunda Médio
Objetos Personalizados Cópia profunda Médio
SendPort Passagem por referência Rápido
Closures de Função Passagem via Isolate.run Verificado em tempo de compilação
⚠️ Nota: Dados transferidos entre Isolates são copiados, não compartilhados. Passar listas grandes incorre em custo de cópia. Para dados grandes, considere transferir em pedaços ou usar closures com Isolate.run.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependente da versão do SDK.

: Melhor Prática para Passagem de Dados Grandes

DART
import 'dart:isolate';

// Passar dados via closure (Isolate.run)
Future<double> processLargeData(List<double> amounts) async {
  return Isolate.run(() {
    // amounts é copiado para dentro do isolate
    double sum = 0;
    for (final a in amounts) {
      sum += a;
    }
    return sum;
  });
}

// Melhor: passar apenas o necessário
Future<double> processChunkOptimized(List<double> chunk) async {
  return Isolate.run(() => chunk.fold(0.0, (a, b) => a + b));
}

void main() async {
  final data = List.generate(1000000, (i) => (i + 1) * 1.0);

  // Dividir e processar em paralelo
  final chunkSize = data.length ~/ 4;
  final futures = List.generate(4, (i) {
    final chunk = data.sublist(i * chunkSize, (i + 1) * chunkSize);
    return Isolate.run(() => chunk.fold(0.0, (a, b) => a + b));
  });

  final results = await Future.wait(futures);
  final total = results.fold(0.0, (a, b) => a + b);
  print('Total: $total');
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependente da versão do SDK.

7. Cenário do Bob: Processamento Paralelo de Um Milhão de Pedidos

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependente da versão do SDK.

: Estatísticas Paralelas do DataPipeline

DART
import 'dart:isolate';

class ChunkResult {
  final int processed;
  final int skipped;
  final double revenue;
  final Map<String, double> categoryRevenue;

  ChunkResult({
    required this.processed,
    required this.skipped,
    required this.revenue,
    required this.categoryRevenue,
  });
}

ChunkResult processChunk(List<Map<String, dynamic>> chunk) {
  int processed = 0;
  int skipped = 0;
  double revenue = 0;
  final categoryRevenue = <String, double>{};

  for (final order in chunk) {
    final amount = order['amount'] as double;
    final status = order['status'] as String;
    final category = order['category'] as String;

    if (amount <= 0 || status == 'cancelled') {
      skipped++;
      continue;
    }

    processed++;
    revenue += amount;
    categoryRevenue.update(category, (v) => v + amount, ifAbsent: () => amount);
  }

  return ChunkResult(
    processed: processed,
    skipped: skipped,
    revenue: revenue,
    categoryRevenue: categoryRevenue,
  );
}

Future<void> main() async {
  // Gerar 1,2M pedidos
  final categories = ['Electronics', 'Books', 'Clothing', 'Home', 'Sports'];
  final statuses = ['completed', 'completed', 'completed', 'pending', 'cancelled'];
  final orders = List.generate(1200000, (i) => {
    'id': 'ORD-${i.toString().padLeft(6, '0')}',
    'amount': (i % 500 + 10) * 1.0,
    'status': statuses[i % statuses.length],
    'category': categories[i % categories.length],
  });

  // Dividir em pedaços
  final isolateCount = 4;
  final chunkSize = orders.length ~/ isolateCount;
  final chunks = List.generate(isolateCount, (i) {
    final start = i * chunkSize;
    final end = i == isolateCount - 1 ? orders.length : (i + 1) * chunkSize;
    return orders.sublist(start, end);
  });

  // Processar em paralelo
  final stopwatch = Stopwatch()..start();
  final results = await Future.wait(
    chunks.map((chunk) => Isolate.run(() => processChunk(chunk))),
  );
  stopwatch.stop();

  // Agregar resultados
  int totalProcessed = 0;
  int totalSkipped = 0;
  double totalRevenue = 0;
  final totalCategoryRevenue = <String, double>{};

  for (final r in results) {
    totalProcessed += r.processed;
    totalSkipped += r.skipped;
    totalRevenue += r.revenue;
    for (final entry in r.categoryRevenue.entries) {
      totalCategoryRevenue.update(entry.key, (v) => v + entry.value, ifAbsent: () => entry.value);
    }
  }

  print('=== Relatório Paralelo do DataPipeline ===');
  print('Pedidos:    ${orders.length}');
  print('Processados: $totalProcessed');
  print('Ignorados:   $totalSkipped');
  print('Receita:   \$${totalRevenue.toStringAsFixed(2)} USD');
  print('Tempo:      ${stopwatch.elapsedMilliseconds}ms');
  print('Isolates:  $isolateCount');

  print('\nPor Categoria:');
  for (final entry in totalCategoryRevenue.entries.toList()..sort((a, b) => b.value.compareTo(a.value))) {
    print('  ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD');
  }
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependente da versão do SDK.

8. Exemplo Completo: Framework de Processamento Paralelo com Isolates do DataPipeline

DART
// ============================================
// Processamento Paralelo com Isolates do DataPipeline
// Framework para análise de dados em paralelo
// ============================================

import 'dart:isolate';

// Resultado do worker
class WorkerResult {
  final int workerId;
  final int processed;
  final int skipped;
  final double revenue;
  final Map<String, double> categoryRevenue;
  final Duration processingTime;

  WorkerResult({
    required this.workerId,
    required this.processed,
    required this.skipped,
    required this.revenue,
    required this.categoryRevenue,
    required this.processingTime,
  });
}

// Função worker - roda em isolate separado
WorkerResult processInIsolate((int, List<Map<String, dynamic>>) input) {
  final (workerId, orders) = input;
  final stopwatch = Stopwatch()..start();

  int processed = 0;
  int skipped = 0;
  double revenue = 0;
  final categoryRevenue = <String, double>{};

  for (final order in orders) {
    final amount = (order['amount'] as num).toDouble();
    final status = order['status'] as String;
    final category = order['category'] as String;

    if (amount <= 0 || status == 'cancelled') {
      skipped++;
      continue;
    }

    processed++;
    revenue += amount;
    categoryRevenue.update(category, (v) => v + amount, ifAbsent: () => amount);
  }

  stopwatch.stop();

  return WorkerResult(
    workerId: workerId,
    processed: processed,
    skipped: skipped,
    revenue: revenue,
    categoryRevenue: categoryRevenue,
    processingTime: stopwatch.elapsed,
  );
}

// Gerenciador de pipeline paralelo
class ParallelPipeline {
  final int isolateCount;

  ParallelPipeline({this.isolateCount = 4});

  Future<void> process(List<Map<String, dynamic>> orders) async {
    print('=== Processamento Paralelo do DataPipeline ===');
    print('Pedidos: ${orders.length}, Isolates: $isolateCount');

    // Dividir pedidos em pedaços
    final chunkSize = orders.length ~/ isolateCount;
    final chunks = List.generate(isolateCount, (i) {
      final start = i * chunkSize;
      final end = i == isolateCount - 1 ? orders.length : (i + 1) * chunkSize;
      return (i, orders.sublist(start, end));
    });

    // Processar em paralelo
    final totalStopwatch = Stopwatch()..start();
    final results = await Future.wait(
      chunks.map((chunk) => Isolate.run(() => processInIsolate(chunk))),
    );
    totalStopwatch.stop();

    // Agregar
    int totalProcessed = 0;
    int totalSkipped = 0;
    double totalRevenue = 0;
    final totalCategoryRevenue = <String, double>{};

    print('\nResultados dos Workers:');
    for (final r in results) {
      totalProcessed += r.processed;
      totalSkipped += r.skipped;
      totalRevenue += r.revenue;
      for (final entry in r.categoryRevenue.entries) {
        totalCategoryRevenue.update(
          entry.key, (v) => v + entry.value, ifAbsent: () => entry.value);
      }
      print('  Worker ${r.workerId}: ${r.processed} processados, '
          '${r.processingTime.inMilliseconds}ms');
    }

    print('\n--- Relatório Agregado ---');
    print('Processados:  $totalProcessed pedidos');
    print('Ignorados:    $totalSkipped registros');
    print('Receita:    \$${totalRevenue.toStringAsFixed(2)} USD');
    print('Tempo total:  ${totalStopwatch.elapsedMilliseconds}ms');

    print('\nPor Categoria:');
    final sorted = totalCategoryRevenue.entries.toList()
      ..sort((a, b) => b.value.compareTo(a.value));
    for (final entry in sorted) {
      final pct = (entry.value / totalRevenue * 100).toStringAsFixed(1);
      print('  ${entry.key}: \$${entry.value.toStringAsFixed(2)} USD ($pct%)');
    }
  }
}

void main() async {
  // Gerar dados de exemplo
  final categories = ['Electronics', 'Books', 'Clothing', 'Home', 'Sports'];
  final statuses = ['completed', 'completed', 'completed', 'pending', 'cancelled'];
  final orders = List.generate(500000, (i) => <String, dynamic>{
    'id': 'ORD-${i.toString().padLeft(6, '0')}',
    'amount': (i % 500 + 10) * 1.0,
    'status': statuses[i % statuses.length],
    'category': categories[i % categories.length],
  });

  final pipeline = ParallelPipeline(isolateCount: 4);
  await pipeline.process(orders);
}
TEXT 📖 Somente leitura
> **Saída:** Execute no DartPad local ou com `dart run`. Todos os exemplos do curso Dart são baseados em Dart 3.x / Flutter 3.x. Os resultados podem variar ligeiramente dependendo da versão do SDK.

❓ Perguntas Frequentes

P: Qual a diferença entre um Isolate e uma Thread? R: Um Isolate possui sua própria memória heap independente e não compartilha dados; Threads compartilham a memória heap. Isolates se comunicam via passagem de mensagens, enquanto Threads se comunicam via variáveis compartilhadas + locks. Isolates não têm race conditions.

P: É custoso criar um Isolate? R: Criar um Isolate leva cerca de 50-150ms, o que é mais lento que criar uma thread. Criar e destruir frequentemente é ineficiente; é recomendado usar um Isolate Pool ou Isolate.run (que gerencia o ciclo de vida automaticamente).

P: Qual a diferença entre Isolate.run e Isolate.spawn? R: Isolate.run é uma API simplificada que executa uma tarefa única e depois fecha o Isolate automaticamente. Isolate.spawn cria um Isolate persistente, exigindo gerenciamento manual do ciclo de vida e comunicação.

P: Os dados são copiados ao serem transferidos entre Isolates? R: Sim. Todos os dados transferidos são copiados profundamente (exceto SendPort). Passar listas grandes tem custo de desempenho. Para dados muito grandes, considere transferir em pedaços.

P: Quantos tipos de Isolates o Dart possui? R: Principalmente dois: o Isolate de uso geral para paralelismo e o compute do Flutter para isolamento de UI. A plataforma web não suporta Isolates reais e usa Web Workers como simulação.

P: Existe um limite superior para o número de Isolates? R: Não há limite rígido, mas cada Isolate ocupa cerca de 2MB de memória. Na prática, é recomendado não exceder o número de núcleos da CPU para evitar troca de contexto excessiva.

P: Para quais cenários os Isolates são adequados? R: Computações intensivas de CPU (análise de dados, processamento de imagens, cálculos criptográficos). Para tarefas intensivas de I/O, Future/Stream é suficiente e Isolates não são necessários.


📖 Resumo


📝 Exercícios

  1. Básico (⭐): Use Isolate.run para calcular o 42º número de Fibonacci e compare o tempo com o cálculo síncrono na thread principal.
  2. Intermediário (⭐⭐): Gere 1.000.000 de números aleatórios, divida-os em 4 partes e use 4 Isolates para calcular a soma e a média de cada parte em paralelo. Finalmente, agregue os resultados no Isolate principal.
  3. Desafio (⭐⭐⭐): Implemente um Isolate Pool usando Isolate.spawn: Pré-crie N Worker Isolates, faça o Isolate principal distribuir tarefas via SendPort, e faça os Workers retornarem resultados após o processamento. Suporte fila de tarefas e balanceamento de carga.

← Lição Anterior | Próxima Lição →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%