Flutter can implement async, awite, and Futrue asynchronously, but these are essentially the same as the Handle queue. Besides, the message queue runs in the UI thread. If you really have any time-consuming operations there, there will be no problem. So do you want to start new threads or do you want to start new threads? Let’s talk about how to communicate between new Isolate and Isolate, but let’s look at the simple function compute
Creation of the ISOLates and communication between them
Each of the isolates is memory isolated, and each of the isolates executes messages in queues. This is a characteristic of the ISOLates. The concepts between languages are basically similar, but the implementation is slightly different. However, due to the similarity in concept, the same requirements will naturally arise. Dart provides a port for communication between isolates
Ports come in pairs and are divided into: ReceivePort Receives port and SendPort sends port. SendPort can generate SendPort by itself. As long as SendPort is passed to the other party, the permission from SendPort->receivePort can be implemented. Of course, this is a single item, two-way communication is also the same, the opposite side of their own SendPort to pass it
var receivePort = ReceivePort();
var sendPort = receivePort.sendPort;
Copy the code
The APIS for creating Isolate are: Await Isolate. Spawn (Function,SendPort), because it is an asynchronous operation, add await, Function is a method, it is the core method that the new thread executes, same meaning as run method, SendPort is the communicator we want to send to the other side
var anotherIsolate = await Isolate.spawn(otherIsolateInit, receivePort.sendPort);
Copy the code
Listen We can get data from the Isolate. All data types can be transmitted between the Isolate without making any marks. It must be realized by the underlying layer
receivePort.listen((date) {
print("Isolate 1 Receives messages: data = $date");
});
Copy the code
Receiveport. first can wait to get the first return result, but cannot be written with receivePort.listen
final sendPort = await receivePort.first as SendPort;
Copy the code
Shutting down the Isolate is straightforward. Call the kill method on the Isolate that it controls within the Main Isolate
void stop(){
print("kill isolate"); isolate? .kill(priority: Isolate.immediate); isolate =null;
}
Copy the code
No nonsense, the above is very simple, put the principle we all understand, the following direct look at the code:
Isolate one-way communication
Isolate the code:
import 'dart:isolate';
var anotherIsolate;
var value = "Now Thread!";
void startOtherIsolate() async {
var receivePort = ReceivePort();
anotherIsolate = await Isolate.spawn(otherIsolateInit, receivePort.sendPort);
receivePort.listen((date) {
print("Isolate 1 accepts messages: data = $date, value = $value");
});
}
void otherIsolateInit(SendPort sendPort) async {
value = "Other Thread!";
sendPort.send("BB");
}
Copy the code
Run code:
import 'DartLib.dart';
void main(){
startOtherIsolate();
}
Copy the code
Results:
Isolate 1 Receives messages: data = BB, value = Now Thread!Copy the code
Isolate two-way communication
Isolate the code:
import 'dart:isolate';
var anotherIsolate;
var value = "Now Thread!";
void startOtherIsolate() async {
var receivePort = ReceivePort();
var sendPort;
anotherIsolate = await Isolate.spawn(otherIsolateInit, receivePort.sendPort);
receivePort.listen((date) {
if (date is SendPort) {
sendPort = date as SendPort;
print("Two-way communication established successfully");
return;
}
print("Isolate 1 Receives messages: data = $date");
sendPort.send("AA");
});
}
void otherIsolateInit(SendPort sendPort) async {
value = "Other Thread!";
var receivePort = ReceivePort();
print("Isolate 2 received a port from Isolate 1 and attempted to establish two-way communication with Isolate 1");
receivePort.listen((date) {
print("Isolate 2 Receives messages: data = $date");
});
sendPort.send(receivePort.sendPort);
for (var index = 0; index < 10; index++) {
sendPort.send("BB$index"); }}Copy the code
Run code:
import 'DartLib.dart';
void main(){
startOtherIsolate();
}
Copy the code
Running results:
Isolate 2Received from the Isolate1Port, try to establish the same as the Isolate1The two - way communication has been established1Receiving messages: data = BB0 Isolate1Receive messages: data = BB1 Isolate1Receive messages: data = BB2 Isolate1Receive messages: data = BB3 Isolate1Receiving messages: Data = BB4 Isolate1Receive messages: data = BB5 Isolate1Receive messages: data = BB6 Isolate1Receive messages: data = BB7 Isolate1Receive messages: data = BB8 Isolate1Receiving messages: Data = BB9 Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receiving messages: Data = AA Isolate2Receive message: data = AACopy the code
System API: computer function
It’s a bit of a hassle to create a new Isoalte and implement the communication. The code is basically repetitive from a encapsulation perspective, so Google provides an API to do this: compute method
The compute method is provided by Flutter (remember not Dart). Compute creates an Isolate inside of Flutter and returns the result of the computation
Compute (function, value) compute takes two parameters, the first one is the core method of the new thread, the second one is the parameter passed from the new thread. Function Function parameters should be designed to match values
Compute method in the import ‘package: flutter/foundation. The dart’ inside the package
Here's an example:
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
void newTask() async {
print("Start time calculation, current ISOLATE =${Isolate.current.toString()}");
var result = await compute(getName, "name");
print(result);
}
String getName(String name) {
print("Getting results... , current ISOLATE =${Isolate.current.toString()}");
sleep(Duration(seconds: 2));
return "Name";
}
Copy the code
Run code:
newTask();
Copy the code
I/ FLUTTER (24384): Start time calculation, current ISOLATE = Instance of 'ISOLATE 'I /flutter (24384): Obtaining results... , current ISOLATE = Instance of 'ISOLATE 'I/FLUTTER (24384): NameCopy the code
Compute function
Compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute: compute
// Compute takes two parameters, as we've already seen
Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debugLabel }) async {
// Call callback.toString() if the debugLabel is emptyprofile(() { debugLabel ?? = callback.toString(); });final Flow flow = Flow.begin();
Timeline.startSync('$debugLabel: start', flow: flow);
final ReceivePort resultPort = ReceivePort();
Timeline.finishSync();
// Create the ISOLATE. This is the same as the previous method of creating the ISOLATE
// One more thing, the arguments passed here are classes wrapped in _IsolateConfiguration
final Isolate isolate = await Isolate.spawn<_IsolateConfiguration<Q, R>>(
_spawn,
_IsolateConfiguration<Q, R>(
callback,
message,
resultPort.sendPort,
debugLabel,
flow.id,
),
errorsAreFatal: true,
onExit: resultPort.sendPort,
);
final R result = await resultPort.first;
Timeline.startSync('$debugLabel: end', flow: Flow.end(flow.id));
resultPort.close();
isolate.kill();
Timeline.finishSync();
return result;
}
Copy the code
Isolate Application Scenario
Although THE Isolate is good, it can also be used in appropriate scenarios. Abuse of the Isolate is not recommended. You should use the event loop mechanism of Dart to process asynchronous tasks as much as possible, so as to make full use of the advantages of Dart
So when should you use Future and when should you use Isolate? One of the easiest ways to do this is to choose based on the average time of certain tasks:
- Methods that execute in milliseconds or tens of milliseconds should use the Future
- If a task takes a few hundred milliseconds or more, it is recommended to create a separate Isolate
Beyond that, there are a few scenarios to look at
- JSON decode
- encryption
- Image processing: for example, cropping
- Network request: load resources, images