Write before dawn
80% of the problems are multithreaded.
For a single-threaded program, only one piece of code is executing at a time, and access and changes to the state in memory occur exclusively.
but…
Modern devices are typically multi-core cpus, and for efficiency, they use threads that share content to run code concurrently.
of course…
Sharing content can lead to race conditions, which can cause errors and increase code complexity.
of course…
We can use locks to solve the problem of race conditions.
but…
The use of locks means that if a resource is in use, then subsequent callers (or threads) cannot do anything meaningful other than wait for the task. This is not acceptable even for increasingly high performance devices. Another problem with locks is that they need to be carefully designed. Individual locks are fine, but as more locks are added, deadlock can occur.
Optimistic lock, pessimistic lock are you afraid of?
so…
The Isolate emerged.
Flutter in the Isolate
Before we talk about Isolate, let’s talk a little bit about the asynchronism of Flutter.
There are generally two ways to implement asynchrony: one is multi-threaded, and the other is an event-based asynchronous model. Multi-threaded we don’t mention, the asynchronous model based on event is simply a single thread in an event loop and an event queue, events cycle continuously removed from the event queue to perform, when the loop in a time-consuming event, it will not stop to wait for, but will skip the event continued to perform, when not finished time-consuming event handling, Go back and look at the results of time-consuming events. Thus, time-consuming events do not block the loop, and events after time-consuming events have a chance to be executed.
It is easy to find that this event-based asynchronous model is suitable for I/O intensive time-consuming operations, because I/O time-consuming operations tend to waste time waiting for data to be transmitted or results to be returned, so this asynchronous model is often used for network server concurrency. If you are computationally intensive, you should take advantage of the processor’s multiple cores as much as possible and implement parallel computing.
What does this have to do with Isolate?
The main function of Flutter is wrapped in an isolation domain called the main Isolate. Each Isolate contains an independent memory, an event loop, an event loop queue, and a thread that executes the event loop.
If we do not open a new Isolate, by default all code will run in the main Isolate, which only corresponds to one thread. This is one reason why Flutter is a single thread.
Memory is isolated and objects cannot be accessed directly. Therefore, there is no problem of sharing resources. Therefore, there is no need to consider the headache of multi-threading.
IOS has a similar concept: actors.
Of course, the Isolate is able to communicate with each other through messaging.
but…
Not all objects meet the delivery criteria, and if they do not, the message will fail to be sent.
An 🌰…
If you want to send a List
and…
Blocking one Isolate does not affect other isolates.
so…
You can see that the Isolate is similar in concept to threads and processes, except that each Isolate has separate memory and separate threads that run event loops.
A 🌰
Let’s write a Demo to see the difference between using Isolate and using single-threaded asynchronism:
The above button used the Isolate to perform time-consuming operation, which had almost no impact on THE UI, while the following button performed the same operation, but instead of using the Isolate, it directly used async/await, and the UI was directly stuck.
How to use
There are three ways:
- Dart –
Isolate
的static Future<Isolate> spawnUri()
- Dart –
Isolate
的static Future<Isolate> spawn()
- Flutter – used directly
compute()
spawnUri
SpawnUri has three required parameters:
- The first is the
Uri
, specify a newIsolate
Path to the code file - The second is a parameter list of type
List<String>
- The third is a dynamic message of type
dynamic
Note that the code file used to run the new Isolate must contain a main function, which is the entry method for the new Isolate. The args parameter list in the main function corresponds to the second parameter in the spawnUri. If you do not need to send parameters to the Isolate, you can send an empty List to the Isolate.
It is used less often and cannot be used in Computer campaigns using DATr: UI. Check out this article on THE Isolate for asynchronous programming in the Dart language.
spawn
Spawn takes two required parameters
- Functions to run (time-consuming tasks)
- Dynamic messages, usually used for delivery
main Isolate
的SendPort
object
A quick demo:
void main() {
var totalCount = await createTask();
print($totalCount);
}
Future createTask() async {
final p = ReceivePort();
await Isolate.spawn(calculateInBackground, p.sendPort);
return await p.first;
}
Future doBusyWorkInBackground(SendPort p) {
final totalCount = await calculateCount(5000000000);
// Use exit instead of send to submit efficiency
return Isolate.exit(p, totalCount);
}
// Define a time-consuming task
Future<int> calculateCount(int targetCount) async {
var totalCount = 0;
for (var i = 0; i < targetCount; i++) {
totalCount += i + i + 1;
}
return totalCount;
}
Copy the code
This is basically the code in the createTask and doBusyWorkInBackground methods. Here you can see that there are two concepts, a ReceivePort and a SendPort, and SendPort uses SendPort from ReceivePort. SendPort and ReceivePort are actually channels for communication between two Isolate, but note that this channel is one-way, which means, One pair of SendPort and ReceivePort can transmit messages only from A Isolate to B Isolate. If B needs to transmit messages to A Isolate, another pair of SendPort and ReceivePort is required.
Another point to note here is isolate. exit, which is a syntax introduced after Dart 2.15. Previously, send was used to transmit messages. Then it will also lead to interface lag. The isolate.exit does not make a deep copy of the data, but passes it directly. This implementation also relies on the concept of Isolate groups introduced after Dart 2.15.
The Isolate in the Isolate group shares various internal data structures that represent running programs. Although the Isolate group still prevents sharing access to mutable objects between isolates, the Isolate group uses the shared heap implementation, which makes it possible to pass objects directly. In addition, the Isolate group also makes individual isolates in groups more portable. Because there was no need to initialize the program structure, starting an additional Isolate in an existing Isolate was over 100 times faster than before, and the resulting Isolate consumed 10 to 100 times less memory.
compute
Can see the Dart create a Isolate somewhat tedious, Flutter official further package provides a simpler API, it is to compute, located in the package: Flutter/foundation. The Dart. See how to rewrite the above program using compute:
void main() {
var totalCount = await createTaskByCompute();
print($totalCount);
}
Future createTaskByCompute() async {
return await compute(calculateCount, 5000000000);
}
Copy the code
It takes two required arguments:
- The method to execute
- Dynamic message type, which can be arguments to the function being run
Process continuous stream data
The Demo above deals with single data, and the Isolate can also deal with continuous data. Check out Dart 2.15 and see what you can do with the Isolate. There is a small Demo for streaming data.
Usage scenarios
The Isolate should not be abused. Dart event loops should be used as much as possible to process asynchronous tasks so as to make full use of the Dart language. One of the easiest ways to determine when to use Future and Isolate is based on task time:
- If it takes a few milliseconds or tens of milliseconds, use
Future
- Others that take more time should be used
Isolate
To implement the
Some reference scenarios:
- JSON decode
- encryption
- Image processing: for example, cropping
- Network request: load resources, images
Write after sunset
Since Flutter 2.8.0, the concept of Isolate groups has been introduced and exit is used to pass parameters, which is much better than before.
Reference article:
Dart 2.15 update
Dart language asynchronous programming Isolate
Dry goods | Dart, a concurrent mechanism
Dart 2.15 update the ISOLATE should be used this way
Here’s a video:
Isolates and multithreading in Flutter
OK, that’s the end of this article. How do you praise, Chinese people do not deceive Chinese people you are really handsome.