isolate_manager 2.0.2+1 isolate_manager: ^2.0.2+1 copied to clipboard
A plugin that helps you create multiple isolates for a function, keep it active and compute with it (Also supports Worker.js on Web).
Isolate Manager #
Features #
-
Easy to create multiple isolate for a function, keep it active and comunicate with it.
-
Supports
Worker
on Web (Worker
is the real Isolate on Web). The plugin will useFuture
(andStream
) ifWorker
is not available on the working browser or is not configured. -
Multiple
compute
s are allowed because the plugin will queues the input data and sends it to free isolate later.
Basic Usage (Use build-in function) #
There are multiple ways to use this package, the only thing to notice that the function
have to be a static
or top-level
function to make it works.
Step 1: Create a top-level or static function #
double add(dynamic value) => value[0] + value[1];
Step 2: Create IsolateManager instance for that function #
final isolateManager = IsolateManager.create(
add, // Function that you want to compute
numOfIsolates: 4, // Number of concurrent isolates. Default is 1
);
Step 3: Initialize the instance #
await isolateManager.start();
Step 4: Send and receive data #
You can listen to the result as stream
isolateManager.stream.listen((result) => print(result));
You can send even more times then numOfIsolates
because the plugin will queues the input data and sends it to free isolate later.
// add([10, 20])
final result = await isolateManager.compute([10, 20]);
Build your widget with StreamBuilder
StreamBuilder(
stream: isolateManager.stream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Text('Result of the `add` function: ${snapshot.data}');
},
),
Step 5: Restart the IsolateManager
if you need it #
await isolateManager.restart();
Step 6: Stop IsolateManager
when it finishes work #
await isolateManager.stop();
Advanced Usage (Use your own function) #
You can control everything with this method when you want to create multiple isolates for a function.
Step 1: Create a function of this form #
// Create your own function here
void isolateFunction(dynamic params) {
// Initial the controller for child isolate
final controller = IsolateManagerController<double>(
params,
onDispose: () {
print('Dispose isolateFunction');
}
);
// Get your initialParams.
// Notice that this `initialParams` different from the `params` above.
final initialParams = controller.initialParams;
// Listen to the message receiving from main isolate
controller.onIsolateMessage.listen((message) {
// Do your stuff here
final result = add(message[0], message[1]);
// Send value back to your main process in stream [onMessage]
controller.sendResult(result);
});
}
Step 2: Create IsolateManager instance for your own function #
final isolateManager = IsolateManager.createOwnIsolate(
isolateFunction,
initialParams: 'This is initialParams',
debugMode: true,
);
Step 3: Now you can use everything as above from this step #
Worker Configuration #
-
Step 1: Download isolate_manager/worker/worker.dart or copy the below code to the file named
worker.dart
:worker.dart
// ignore_for_file: avoid_web_libraries_in_flutter, depend_on_referenced_packages import 'dart:async'; import 'dart:convert'; import 'dart:html' as html; import 'dart:js' as js; import 'package:js/js.dart' as pjs; import 'package:js/js_util.dart' as js_util; @pjs.JS('self') external dynamic get globalScopeSelf; // dart compile js worker.dart -o worker.js -O4 main() { callbackToStream('onmessage', (html.MessageEvent e) { return js_util.getProperty(e, 'data'); }).listen((message) async { final Completer completer = Completer(); completer.future.then((value) => jsSendMessage(value)); completer.complete(worker(message)); }); } /// TODO: Modify your function here FutureOr<dynamic> worker(dynamic message) { return message; } Stream<T> callbackToStream<J, T>( String name, T Function(J jsValue) unwrapValue) { var controller = StreamController<T>.broadcast(sync: true); js_util.setProperty(js.context['self'], name, js.allowInterop((J event) { controller.add(unwrapValue(event)); })); return controller.stream; } void jsSendMessage(dynamic m) { js.context.callMethod('postMessage', [jsonEncode(m)]); }
-
Step 2: Modify the function
FutureOr<dynamic> worker(dynamic message)
in the script to serves your purposes. You can also use thetop-level or static function
that you have created above.
You should copy that function to separated file or copy to worker.dart
file to prevent the dart compile js
error because some other functions depend on flutter library.
-
Step 3: Run
dart compile js worker.dart -o worker.js -O4
to compile dart to js (-O0 to -O4 is the obfuscated level ofjs
). -
Step 4: Copy
worker.js
to web folder (the same folder withindex.html
). -
Step 5: Now you can add
worker
toworkerName
like below:final isolateManager = IsolateManager.create( add, workerName: 'worker', // Don't need to add the extension );
Now the plugin will handle all other action to make the real isolate works on Web.
Additional #
-
If the
worker.dart
show errors forjs
package, you can addjs
todev_dependencies
:dev_dependencies: js:
-
The result that you get from the isolate (or Worker) is sometimes different from the result that you want to get from the return type in the main app, you can use
converter
andworkerConverter
parameters to convert the result received from theIsolate
(converter) andWorker
(workerConverter). Example:final isolateManager = IsolateManager.create( convertToMap, // Ex: 'map_result' if the name is 'map_result.js' workerName: 'worker', // Convert the data from worker to fix the issue related to the different data type between dart and js workerConverter: (result) { final Map<int, double> convert = {}; // Convert Map<String, String> (received from Worker) to Map<int, double> final decodedMap = jsonDecode(result) as Map; decodedMap.forEach((key, value) => convert.addAll({int.parse(key): double.parse(value)})); return convert; }, );
Data flow: Main -> Isolate or Worker -> Converter -> Result
Contributions #
- This plugin as an enhanced plugin for
isolate_contactor
: pub | git - If you encounter any problems or feel the library is missing a feature, feel free to open an issue. Pull request are also welcome.
To-do list #
- Find the best way to prevent using
dart compile js
.