Flutter Isolate Worker 🚀
🎬 Demo GIF
A Dart/Flutter package for running heavy or parallelizable tasks in the background using Dart Isolates, with a simple message-based API and worker pool management.
📚 Table of Contents
- Flutter Isolate Worker 🚀
✨ Introduction
flutter_isolate_worker
is a Dart/Flutter package for running heavy or parallelizable tasks in the background using Dart Isolates, with a simple message-based API and convenient worker pool management.
🏗️ Architecture Overview
- WorkerMessage: Defines a task that can be sent to an isolate for execution.
- IsolateWorker: Manages a single isolate, receives and executes WorkerMessages.
- IsolateWorkerPool: Manages multiple IsolateWorkers, supports round-robin or tag-based task assignment, and provides methods to add, pause, resume, or kill workers.
- Event & Logging: Supports event listening and logging for monitoring worker/pool activity.
🧩 Main Components
📦 WorkerMessage
- abstract class WorkerMessage<T, R>
- Represents a unit of work to be sent to an isolate.
- Properties:
id
: String? (auto-generated if not provided)input
: T (input data)
- Method:
FutureOr<R> execute()
: Override to perform the task and return the result.
👷 IsolateWorker
- Manages a single isolate.
- Main methods:
Future<void> start()
: Start the isolate.Future<R> sendMessage<T, R>(WorkerMessage<T, R> message, {Duration? timeout})
: Send a task and get the result.void kill()
: Kill the isolate.void pause()
,void resume()
: Pause/resume receiving tasks.Stream<IsolateWorkerEvent> get events
: Listen to worker events.
👷♂️👷♀️ IsolateWorkerPool
- Manages multiple workers.
- Main methods:
Future<void> start()
: Start all workers in the pool.Future<R> sendMessage<T, R>(WorkerMessage<T, R> message)
: Send a task to the next available worker (round-robin).Future<R> sendMessageToTag<T, R>(String tag, WorkerMessage<T, R> message)
: Send a task to a worker by tag.void add({String? tag})
: Add a new worker.void killByTag(String tag)
,void killAll()
,void killByTags(List<String> tags)
: Kill workers.void pauseWorker(String tag)
,void resumeWorker(String tag)
,void pauseAll()
,void resumeAll()
: Pause/resume workers.List<String> getWorkerTags()
: Get list of worker tags.Stream<IsolateWorkerEvent> listenWorkerEvents()
: Listen to all worker events.Stream<IsolateWorkerEvent> listenWorkerEventsByTag(String tag)
: Listen to events of a specific worker.Stream<IsolateWorkerPoolEvent> get events
: Listen to pool events (add, remove, pause, resume workers).
🔔 Events
- IsolateWorkerEvent: Indicates when a worker receives or completes a task.
- IsolateWorkerPoolEvent: Indicates when the pool adds/removes/pauses/resumes a worker.
🚦 Basic Usage
1️⃣ Define a Task (WorkerMessage)
You need to create a class that extends WorkerMessage and override the execute method:
import 'package:flutter_isolate_worker/flutter_isolate_worker.dart';
class FactorialMessage extends WorkerMessage<int, int> {
FactorialMessage(int input) : super(null, input);
@override
Future<int> execute() async {
int result = 1;
for (int i = 1; i <= input; i++) result *= i;
return result;
}
}
2️⃣ Create and Use IsolateWorkerPool
final pool = IsolateWorkerPool(numIsolates: 2);
await pool.start();
3️⃣ Send Task and Get Result
final result = await pool.sendMessage(FactorialMessage(5));
print('Result: $result'); // 120
Or send to a specific worker:
final result = await pool.sendMessageToTag('worker_1', FactorialMessage(10));
4️⃣ Manage workers: pause, resume, kill, add
pool.pauseWorker('worker_1');
pool.resumeWorker('worker_1');
pool.killByTag('worker_1');
await pool.add(); // Add a new worker
pool.killAll(); // Kill all workers
5️⃣ Listen to events
pool.listenWorkerEvents().listen((event) {
print('Worker event: ${event.type} - ${event.message}');
});
pool.events.listen((event) {
print('Pool event: ${event.type} - ${event.tag}');
});
📝 Full Example
import 'package:flutter_isolate_worker/flutter_isolate_worker.dart';
class SumMessage extends WorkerMessage<List<int>, int> {
SumMessage(List<int> input) : super(null, input);
@override
Future<int> execute() async {
return input.fold(0, (a, b) => a + b);
}
}
void main() async {
final pool = IsolateWorkerPool(numIsolates: 2);
await pool.start();
final result = await pool.sendMessage(SumMessage([1, 2, 3, 4, 5]));
print('Sum: $result'); // 15
pool.listenWorkerEvents().listen((event) {
print('Worker event: ${event.type} - ${event.message}');
});
await pool.add(tag: 'custom_worker');
final result2 = await pool.sendMessageToTag('custom_worker', SumMessage([10, 20]));
print('Sum2: $result2'); // 30
pool.killAll();
}
🛡️ Resource & Memory Management Notes
- Always kill workers when not needed: Call
killByTag
,killAll
, orkillByTags
to free isolates. - Do not create too many isolates: The number of isolates should match your CPU cores.
- Clean up completers: When an isolate is killed, any pending completers are completed with error to avoid leaks.
- Do not send tasks to paused workers: Sending a task to a paused worker will throw a StateError.
🔗 References
If you need a Flutter UI example or more complex tasks (e.g. Fibonacci, large array sorting, API fetching), see the example/
directory in the package.
License
MIT