Skip to content

Instantly share code, notes, and snippets.

@shinayser
Created July 29, 2019 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shinayser/a2cab73dd8a4245dee81f009e61c3977 to your computer and use it in GitHub Desktop.
Save shinayser/a2cab73dd8a4245dee81f009e61c3977 to your computer and use it in GitHub Desktop.
Easy access to Isolate's computing function.
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:developer';
import 'dart:isolate';
import 'package:meta/meta.dart';
const bool kReleaseMode =
bool.fromEnvironment('dart.vm.product', defaultValue: false);
typedef ComputeCallback<Q, R> = FutureOr<R> Function(Q message);
/// The dart:io implementation of [isolate.compute].
Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message,
{String debugLabel}) async {
if (!kReleaseMode) {
debugLabel ??= callback.toString();
}
final Flow flow = Flow.begin();
Timeline.startSync('$debugLabel: start', flow: flow);
final ReceivePort resultPort = ReceivePort();
final ReceivePort errorPort = ReceivePort();
Timeline.finishSync();
final Isolate isolate =
await Isolate.spawn<_IsolateConfiguration<Q, FutureOr<R>>>(
_spawn,
_IsolateConfiguration<Q, FutureOr<R>>(
callback,
message,
resultPort.sendPort,
debugLabel,
flow.id,
),
errorsAreFatal: true,
onExit: resultPort.sendPort,
onError: errorPort.sendPort,
);
final Completer<R> result = Completer<R>();
errorPort.listen((dynamic errorData) {
assert(errorData is List<dynamic>);
assert(errorData.length == 2);
final Exception exception = Exception(errorData[0]);
final StackTrace stack = StackTrace.fromString(errorData[1]);
if (result.isCompleted) {
Zone.current.handleUncaughtError(exception, stack);
} else {
result.completeError(exception, stack);
}
});
resultPort.listen((dynamic resultData) {
assert(resultData == null || resultData is R);
if (!result.isCompleted) result.complete(resultData);
});
await result.future;
Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
resultPort.close();
errorPort.close();
isolate.kill();
Timeline.finishSync();
return result.future;
}
@immutable
class _IsolateConfiguration<Q, R> {
const _IsolateConfiguration(
this.callback,
this.message,
this.resultPort,
this.debugLabel,
this.flowId,
);
final ComputeCallback<Q, R> callback;
final Q message;
final SendPort resultPort;
final String debugLabel;
final int flowId;
R apply() => callback(message);
}
Future<void> _spawn<Q, R>(
_IsolateConfiguration<Q, FutureOr<R>> configuration) async {
R result;
await Timeline.timeSync(
'${configuration.debugLabel}',
() async {
result = await configuration.apply();
},
flow: Flow.step(configuration.flowId),
);
Timeline.timeSync(
'${configuration.debugLabel}: returning result',
() {
configuration.resultPort.send(result);
},
flow: Flow.step(configuration.flowId),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment