actors
actors copied to clipboard
Problems using with Flutter
Hi, sweet api. I tried it with Flutter and encountered number of problems: exceptions not thrown from actor, unreachable code
errors when using with plugins, actor returning nothing. Is it compatible with Flutter?
Example code with path_provider, a common Flutter plugin, actor gets stuck:
class Two with Handler<int, dynamic> {
handle(int i) async {
var p = await getTemporaryDirectory();
print("Found path: $p");
return p;
}
}
runActor() async {
final actor = Actor(Two());
print("SEND");
var res = await actor.send(3).catchError((e) {
print("ERROR: $e");
}).then((res) {
print("RES $res");
});
print('ok $res');
}
Hi! I haven't had the time to use actors in Flutter, but pub says it's compatible. If you have problems it must be related to differences in Isolate
behaviour between DartVM and Flutter runtime.
It could be the problems are simply related to AOT. I will try tonight and see if I can figure this out.
Just tried:
dart --snapshot=run.snapshot --snapshot-kind=app-jit example/actors_example.dart
dart run.snapshot
Runs without problems... It seems the problem is only in Flutter... do you know if there's any issues with Isolates in Flutter?
The code I provided does not even run in Flutter sorry, but at least it throws an exception: I've tested with their compute
function.
After a bit of research it appears that isolates in Flutter can not access plugins neither run platform channel code inside. Also the data provided to the isolate has to be of native Dart type. All these limitations make the isolates in Flutter not very useful at the time.I hope they'll provide some more powerful primitives in the future for real concurrency: I miss Go here! Anyway keep on with your work, the api is great
Ok, I will keep the issue open, so others can see it and not waste too much of their time because of this problem.
Since Dart 2.15, it seems that Flutter now supports Isolates, hence actors, really well!
See this: https://dart.dev/guides/language/concurrency#sending-multiple-messages-between-isolates
Could any Flutter user please let me know if I can close this ticket?
Hey there, just wanted to drop a note and say that I'm using actors
successfully in a Flutter application. I am not using them across MethodChannel
s or anything too crazy, my usage is actually more geared at expensive operations done across thousands of entities which would cause jank without the use of background Isolate
s. A common usage is something like:
/// Returns a `Map` of [Transaction]s grouped by the [LocalDate] they occurred on.
class GroupByDateActor with Handler<List<Transaction>, Map<LocalDate, List<Transaction>>> {
@override
FutureOr<Map<LocalDate, List<Transaction>>> handle(List<Transaction> message) {
// `groupedByDate` is just an extension method on `List<Transaction>` that runs a `fold` operation
// that on large datasets could take ~50ms.
return message.groupedByDate();
}
}
/// Provides a [GroupByDateActor] for use by another [Provider]
final groupByDateActorProvider = Provider((ref) {
final group = Actor.create(() => GroupByDateActor());
ref.onDispose(() async => await group.close());
return group;
});
// In another provider
final groupedByDateActor = ref.watch(groupByDateActorProvider);
final datesToTransactions = await groupedByDateActor.send(expenseTransactions);
This works great and has eliminated frame jank. What I'm struggling with (and which probably deserves its own issue) is the fact(s) that:
-
Spinning up
Isolate
s in debug mode seems to be extremely slow (though I haven't found any conversation on this (womp), so application launch/init is slower than I'd like. In release mode, it's just as fast as without usingIsolate
s. I suspect there's some debugging overhead (like allowing setting breakpoints, etc.) associated with the eachIsolate
being spawned. -
Using
Isolate
s during aflutter_test
is painful, and oftentimes it's preferred to disable/opt out ofIsolate
usage. This is often done via a parameter into whatever component is using the backgroundIsolate
(as seen here in the constructor of this HTTP client). I would like to find a way to swap out my runtime (background -Isolate
-using)Actor
s for "testActor
s" that run their logic on the mainIsolate
.
EDIT: I've just discovered Messenger
(thanks to a great README
) which should allow me to do something like:
final groupByDateActorProvider = Provider<Messenger<List<Transaction>, Map<LocalDate, List<Transaction>>>>((ref) {
// Using `Actor.of` is just a cleanup and removes the need for the separate `GroupByDateActor` class
final actor = Actor.of(
(List<Transaction> message) async => await message.groupedByDate(),
);
ref.onDispose(() async => await actor.close());
return actor;
});
and then during tests (or even at runtime if I want to get fancy) can be overridden with:
groupByDateActorProvider.overrideWith((ref) {
return LocalGroupByDate();
})
class LocalGroupByDate with Messenger<List<Transaction>, Map<LocalDate, List<Transaction>>> {
@override
FutureOr<void> close() {
// Do nothing
}
@override
FutureOr<Map<LocalDate, List<Transaction>>> send(List<Transaction> message) {
return message.groupedByDate();
}
}
Thanks for the report @btrautmann ! I'm glad you found out you can test stuff without Isolates using the local messenger, that was basically why I made actors implement Messenger... but I am surprised Isolates are so slow on debug mode! I've never experienced that myself as I am not using Flutter much.
Anyway, closing this ticket as it seems actors works on Flutter well now.