Módulo 03: Dart Deep Dive

Isolates Concurrencia

Runtime Memoria

# Isolates y Concurrencia en Dart A diferencia de Java o C++, Dart no tiene "hilos" (threads) de memoria compartida. En su lugar, utiliza **Isolates**. ## ¿Qué es un Isolate? Un Isolate es un espacio de ejecución aislado con: - Su propio Event Loop. - Su propia memoria (Heap). - Su propio Stack. **Importante:** Los Isolates **NO comparten memoria**. Para comunicarse, deben enviarse mensajes. ## ¿Cuándo usar Isolates? Usa Isolates cuando tengas tareas que requieran mucho uso de CPU (CPU-bound) y que duren lo suficiente como para causar "jank" (tirones) en la UI (generalmente > 16ms). Ejemplos: - Procesamiento de imágenes (filtros, redimensionado). - Parsing de JSON muy grandes (> 1MB). - Cifrado/Descifrado de datos. - Cálculos matemáticos complejos. ## `Isolate.run` (Dart 2.19+) La forma más moderna y sencilla de ejecutar código en otro isolate. ```dart import 'dart:isolate'; // Función pesada (debe ser estática o top-level) int fibonacci(int n) { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); } void main() async { print('Iniciando cálculo...'); // Ejecuta fibonacci(40) en otro isolate y devuelve el resultado // El hilo principal NO se bloquea final resultado = await Isolate.run(() => fibonacci(40)); print('Resultado: $resultado'); } ``` ## `compute` en Flutter En Flutter, a menudo usamos la función `compute`, que es un wrapper conveniente sobre Isolates. ```dart import 'package:flutter/foundation.dart'; // Parsing JSON pesado List parseUsers(String responseBody) { final parsed = jsonDecode(responseBody).cast>(); return parsed.map((json) => User.fromJson(json)).toList(); } Future> fetchUsers() async { final response = await http.get(Uri.parse('https://api.com/users')); // Mueve el parsing y mapeo a un hilo de fondo return compute(parseUsers, response.body); } ``` ## Comunicación Bidireccional (Ports) Para casos más complejos donde necesitas comunicación continua (streaming de datos), usas `SendPort` y `ReceivePort`. ```dart import 'dart:isolate'; void worker(SendPort mainSendPort) { final workerReceivePort = ReceivePort(); // 1. Enviar el puerto del worker al main mainSendPort.send(workerReceivePort.sendPort); // 2. Escuchar mensajes del main workerReceivePort.listen((message) { if (message is int) { final result = message * 2; mainSendPort.send(result); } }); } void main() async { final mainReceivePort = ReceivePort(); // Iniciar Isolate await Isolate.spawn(worker, mainReceivePort.sendPort); // Obtener el puerto del worker final SendPort workerSendPort = await mainReceivePort.first; // Crear un nuevo puerto para recibir respuestas final responsePort = ReceivePort(); // Enviar trabajo workerSendPort.send(10); workerSendPort.send(20); // Escuchar respuestas // Nota: En un caso real, necesitarías lógica para correlacionar respuestas } ``` ## Limitaciones 1. **Copia de Mensajes:** Al pasar datos entre isolates, estos se copian (deep copy), lo cual puede ser lento para objetos muy grandes. 2. **Plataforma Web:** En Dart Web, los Isolates se compilan a Web Workers, pero tienen limitaciones (no comparten memoria, serialización JS). ## Conclusión - Dart es single-threaded por defecto. - Usa **Isolates** para paralelismo real (multi-core). - `Isolate.run` es la forma moderna para tareas "fire-and-forget". - Los Isolates no comparten memoria, se comunican por mensajes.

Este apartado profundiza en los conceptos clave, proporcionando ejemplos prácticos y mejores prácticas para su aplicación en proyectos reales.

Al comprender estos detalles, podrás diseñar soluciones más robustas, mantenibles y escalables en tus aplicaciones Flutter y Dart.