Skip to content

Spawning 16 (or more) [Isolate]s with [sleep] freeze the application #51254

Closed
@alexmercerind

Description

@alexmercerind

Hi! I'm in a situation where I'm using Isolates 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:

  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.

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.library-isolate

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions