Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 3219da9

Browse files
authored
Use Isolate.run as implementation for compute (#115779)
1 parent 8b32ac7 commit 3219da9

File tree

1 file changed

+4
-137
lines changed

1 file changed

+4
-137
lines changed

packages/flutter/lib/src/foundation/_isolates_io.dart

+4-137
Original file line numberDiff line numberDiff line change
@@ -3,151 +3,18 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6-
import 'dart:developer';
76
import 'dart:isolate';
8-
import 'package:meta/meta.dart';
97

108
import 'constants.dart';
119
import 'isolates.dart' as isolates;
1210

1311
export 'isolates.dart' show ComputeCallback;
1412

1513
/// The dart:io implementation of [isolate.compute].
16-
Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, { String? debugLabel }) async {
14+
Future<R> compute<Q, R>(isolates.ComputeCallback<Q, R> callback, Q message, {String? debugLabel}) async {
1715
debugLabel ??= kReleaseMode ? 'compute' : callback.toString();
1816

19-
final Flow flow = Flow.begin();
20-
Timeline.startSync('$debugLabel: start', flow: flow);
21-
final RawReceivePort port = RawReceivePort();
22-
Timeline.finishSync();
23-
24-
void timeEndAndCleanup() {
25-
Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
26-
port.close();
27-
Timeline.finishSync();
28-
}
29-
30-
final Completer<dynamic> completer = Completer<dynamic>();
31-
port.handler = (dynamic msg) {
32-
timeEndAndCleanup();
33-
completer.complete(msg);
34-
};
35-
36-
try {
37-
await Isolate.spawn<_IsolateConfiguration<Q, R>>(
38-
_spawn,
39-
_IsolateConfiguration<Q, R>(
40-
callback,
41-
message,
42-
port.sendPort,
43-
debugLabel,
44-
flow.id,
45-
),
46-
onExit: port.sendPort,
47-
onError: port.sendPort,
48-
debugName: debugLabel,
49-
);
50-
} on Object {
51-
timeEndAndCleanup();
52-
rethrow;
53-
}
54-
55-
final dynamic response = await completer.future;
56-
if(response == null) {
57-
throw RemoteError('Isolate exited without result or error.', '');
58-
}
59-
60-
assert(response is List<dynamic>);
61-
response as List<dynamic>;
62-
63-
final int type = response.length;
64-
assert(1 <= type && type <= 3);
65-
66-
switch (type) {
67-
// success; see _buildSuccessResponse
68-
case 1:
69-
return response[0] as R;
70-
71-
// native error; see Isolate.addErrorListener
72-
case 2:
73-
await Future<Never>.error(RemoteError(
74-
response[0] as String,
75-
response[1] as String,
76-
));
77-
78-
// caught error; see _buildErrorResponse
79-
case 3:
80-
default:
81-
assert(type == 3 && response[2] == null);
82-
83-
await Future<Never>.error(
84-
response[0] as Object,
85-
response[1] as StackTrace,
86-
);
87-
}
88-
}
89-
90-
@immutable
91-
class _IsolateConfiguration<Q, R> {
92-
const _IsolateConfiguration(
93-
this.callback,
94-
this.message,
95-
this.resultPort,
96-
this.debugLabel,
97-
this.flowId,
98-
);
99-
final isolates.ComputeCallback<Q, R> callback;
100-
final Q message;
101-
final SendPort resultPort;
102-
final String debugLabel;
103-
final int flowId;
104-
105-
FutureOr<R> applyAndTime() {
106-
return Timeline.timeSync(
107-
debugLabel,
108-
() => callback(message),
109-
flow: Flow.step(flowId),
110-
);
111-
}
112-
}
113-
114-
/// The spawn point MUST guarantee only one result event is sent through the
115-
/// [SendPort.send] be it directly or indirectly i.e. [Isolate.exit].
116-
///
117-
/// In case an [Error] or [Exception] are thrown AFTER the data
118-
/// is sent, they will NOT be handled or reported by the main [Isolate] because
119-
/// it stops listening after the first event is received.
120-
///
121-
/// Also use the helpers [_buildSuccessResponse] and [_buildErrorResponse] to
122-
/// build the response
123-
Future<void> _spawn<Q, R>(_IsolateConfiguration<Q, R> configuration) async {
124-
late final List<dynamic> computationResult;
125-
126-
try {
127-
computationResult = _buildSuccessResponse(await configuration.applyAndTime());
128-
} catch (e, s) {
129-
computationResult = _buildErrorResponse(e, s);
130-
}
131-
132-
Isolate.exit(configuration.resultPort, computationResult);
133-
}
134-
135-
/// Wrap in [List] to ensure our expectations in the main [Isolate] are met.
136-
///
137-
/// We need to wrap a success result in a [List] because the user provided type
138-
/// [R] could also be a [List]. Meaning, a check `result is R` could return true
139-
/// for what was an error event.
140-
List<R> _buildSuccessResponse<R>(R result) {
141-
return List<R>.filled(1, result);
142-
}
143-
144-
/// Wrap in [List] to ensure our expectations in the main isolate are met.
145-
///
146-
/// We wrap a caught error in a 3 element [List]. Where the last element is
147-
/// always null. We do this so we have a way to know if an error was one we
148-
/// caught or one thrown by the library code.
149-
List<dynamic> _buildErrorResponse(Object error, StackTrace stack) {
150-
return List<dynamic>.filled(3, null)
151-
..[0] = error
152-
..[1] = stack;
17+
return Isolate.run<R>(() {
18+
return callback(message);
19+
}, debugName: debugLabel);
15320
}

0 commit comments

Comments
 (0)