Description
Hi! I'm in a situation where I'm using Isolate
s to "poll" for events. But as soon as there are more than 16 isolates in Dart SDK or 8 in Flutter, whole application freezes. Please refer to code below.
Expected Behavior
"Alive!" is printed out to the console every second.
Actual Behavior
No output is ever printed out to the console as if application is frozen.
When using the following code in Dart SDK & Flutter:
- Dart SDK: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 16.
- Flutter: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 8.
Once kIsolateSpawnCount is set to 15 in Dart SDK or 7 in Flutter, "Alive!" is printed every second as expected.
Dart Example
import 'dart:io';
import 'dart:async';
import 'dart:isolate';
/// Expected Behavior
/// -----------------
/// "Alive!" is printed out to the console every second.
///
/// Actual Behavior
/// ---------------
/// No output is ever printed out to the console as if application is frozen.
/// When using the following code in Dart SDK & Flutter:
/// 1. Dart SDK: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 16.
/// 2. Flutter: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 8.
///
/// Once [kIsolateSpawnCount] is set to 15 in Dart SDK or 7 in Flutter, "Alive!" is printed every second as expected.
///
const kIsolateSpawnCount = 16;
void isolate(message) {
// [sleep]ing one [Isolate] should not affect rest of the [Isolate]s, main [Isolate] or the event loop.
// Note: [Future.delayed] works as intended.
sleep(const Duration(days: 1));
}
Future<void> main() async {
for (int i = 0; i < kIsolateSpawnCount; i++) {
await Isolate.spawn(isolate, null);
}
Timer.periodic(
const Duration(seconds: 1),
(e) {
print('Alive!');
},
);
}
Flutter Example
import 'dart:io';
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/material.dart';
/// Expected Behavior
/// -----------------
/// "Alive!" is printed out to the console every second.
///
/// Actual Behavior
/// ---------------
/// No output is ever printed out to the console as if application is frozen.
/// When using the following code in Dart SDK & Flutter:
/// 1. Dart SDK: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 16.
/// 2. Flutter: "Alive!" is printed as long as [kIsolateSpawnCount] is less than 8.
///
/// Once [kIsolateSpawnCount] is set to 15 in Dart SDK or 7 in Flutter, "Alive!" is printed every second as expected.
///
const kIsolateSpawnCount = 8;
void isolate(message) {
// [sleep]ing one [Isolate] should not affect rest of the [Isolate]s, main [Isolate] or the event loop.
// Note: [Future.delayed] works as intended.
sleep(const Duration(days: 1));
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
for (int i = 0; i < kIsolateSpawnCount; i++) {
await Isolate.spawn(isolate, null);
}
Timer.periodic(
const Duration(seconds: 1),
(e) {
debugPrint('Alive!');
},
);
});
}
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('test'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const HomeScreen(),
),
);
},
child: const Text('Go!'),
),
),
);
}
}
dart --version
Dart SDK version: 2.18.6 (stable) (Tue Dec 13 21:15:14 2022 +0000) on "windows_x64"
I assume Flutter spawns it's own isolates. I don't know however, I have limited knowledge of this.
I'm working on package:media_kit
& one of the users recently reported that as soon as they create 8 Player
instances, everything freezes up. I could reduce down problem to the code I shared above. Still, you can see these lines which run on another Isolate
for every instance of Player
, where I'm calling mpv_wait_event
, passing negative duration means waiting until next event comes up.
Now I'm considering to create a separate shared library which will do the "polling" using C++'s std::thread
, but it will be a pain & hacky approach to ship another shared library separately for each platform (while rest of the code is in 100% Dart).
On the other hand, using Isolate
already present in Dart SDK was handy & worked correctly.
Any guidance or explanation will be really helpful.
Thanks!