Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels "Futures - Isolates - Event Loop" von Didier Boelens über Asynchronität und Multithreading in Dart
(und Flutter
insbesondere).
TLDR: , . Event Loop, Future async/await (, JavaScript), otlin, , . , .
Und über die Übersetzung der Begriffe. In gesprochener Sprachewir Ich sage "Streams", "Trades", "Futures" usw., während diese Begriffe im Druck seltsam und ungeschickt aussehen.
Gleichzeitig ist es Stream
ein Stream und Thread
- ein Stream. Der Kontext wird in diesem Fall nicht immer gespeichert. Das gleiche Isolat klingt fĂĽr meinen Geschmack auf Russisch normal, also verwende ich irgendwo die Schreibweise auf Kyrillisch und irgendwo im Original.
Hier und da in Klammern nach russischen Wörtern ihr englisches Original, manchmal auch umgekehrt.
EinfĂĽhrung
Vor kurzem habe ich oft Fragen zu den Begriffen im Zusammenhang Future
, async
, await
, Isolate
und die parallelen AusfĂĽhrung von Code.
DarĂĽber hinaus haben einige Entwickler Probleme, die Reihenfolge der AusfĂĽhrung ihres Codes zu verstehen.
Ich beschloss, die Gelegenheit zu nutzen und diesen Themen einen Artikel zu widmen. Gleichzeitig werde ich versuchen, die Verwirrung zu beseitigen, die hauptsächlich mit den Konzepten von
und verbunden ist
.
Dart
- Single-Threaded-Sprache
, Dart
— Flutter
Dart
.
Dart
. . , .
, ( ), , .
void myBigLoop(){
for (int i = 0; i < 1000000; i++){
_doSomethingSynchronously();
}
}
, myBigLoop()
. , - ,
, .
Dart
Dart
, , Event Loop
.
Flutter
- ( Dart
-), — Thread
, —
(Isolate
). , .
, :
- (
Queues
) MicroTask
()
Event
(), FIFO
(.: first in first out, .. ,
, ), main()
,Event Loop
( )
,
Event Loop
, : MicroTask
Event
.
Event Loop
"" ,
"". ,
Dart
-, "" :
void eventLoop(){
while (microTaskQueue.isNotEmpty){
fetchFirstMicroTaskFromQueue();
executeThisMicroTask();
return;
}
if (eventQueue.isNotEmpty){
fetchFirstEventFromQueue();
executeThisEventRelatedCode();
}
}
, MicroTask
Event
. ?
MicroTask
,
, - , Event Loop
.
. - , - :
MyResource myResource;
...
void closeAndRelease() {
scheduleMicroTask(_dispose);
_close();
}
void _close(){
// ,
//
...
}
void _dispose(){
// ,
// , _close()
//
}
-, , . ,
scheduleMicroTask()
7 . Event
.
Event
, :
, , Event
.
, MicroTask
, Event Loop
Event
.
, Futures
Event
.
Futures
Future
,
( ) - .
, Future
:
- ,
Dart
- ,
Future
,
Event
Future
(incomplete)- , (
Future
)
, Future
Event
,
Event Loop
.
( ) then()
catchError()
Future
.
, :
void main(){
print('Before the Future');
Future((){
print('Running the Future');
}).then((_){
print('Future is complete');
});
print('After the Future');
}
, :
Before the Future
After the Future
Running the Future
Future is complete
:
print('Before the Future')
(){print('Running the Future');}
Event
print('After the Future')
Event Loop
2- ,
then()
:
Future
, , Event Loop
(async)
async
, Dart
, :
- —
Future
- ,
await
, Future
, await
, await
, [ Future], .
Event Loop
...
,
,
void main() async {
methodA();
await methodB();
await methodC('main');
methodD();
}
methodA(){
print('A');
}
methodB() async {
print('B start');
await methodC('B');
print('B end');
}
methodC(String from) async {
print('C start from $from');
Future((){ // <== -
print('C running Future from $from');
}).then((_){
print('C end of Future from $from');
});
print('C end from $from');
}
methodD(){
print('D');
}
:
A
B start
C start from B
C end from B
B end
C start from main
C end from main
D
C running Future from B
C end of Future from B
C running Future from main
C end of Future from main
, methodC()
. , , .
, methodD()
, :
void main() async {
methodA();
await methodB();
await methodC('main');
methodD();
}
methodA(){
print('A');
}
methodB() async {
print('B start');
await methodC('B');
print('B end');
}
methodC(String from) async {
print('C start from $from');
await Future((){ // <==
print('C running Future from $from');
}).then((_){
print('C end of Future from $from');
});
print('C end from $from');
}
methodD(){
print('D');
}
:
A
B start
C start from B
C running Future from B
C end of Future from B
C end from B
B end
C start from main
C running Future from main
C end of Future from main
C end from main
D
, await
Future
methodC()
.
:
, , Event Loop
. . method1
— method2
? ?
void method1(){
List<String> myArray = <String>['a','b','c'];
print('before loop');
myArray.forEach((String value) async {
await delayedPrint(value);
});
print('end of loop');
}
void method2() async {
List<String> myArray = <String>['a','b','c'];
print('before loop');
for(int i=0; i<myArray.length; i++) {
await delayedPrint(myArray[i]);
}
print('end of loop');
}
Future<void> delayedPrint(String value) async {
await Future.delayed(Duration(seconds: 1));
print('delayedPrint: $value');
}
: .
, method1
forEach()
. , async
( Future
). await
, Event
. , : print('end of loop')
. Event Loop
3 .
method2
, ( ) — .
, ,
Event Loop
...
, Flutter
? ?
, Isolate
().
, Isolate
Dart
Thread
().
Thread
.
Flutter
.
.
Event Loop
.
(MicroTask
Event
).
.
Dart
.
, .
1.
() API, Dart
.
1.1. 1:
,
, , "" ""
.
, ,
. SendPort
( , , /, ).
, "" " " , "". :
//
//
//
//
//
SendPort newIsolateSendPort;
//
//
//
Isolate newIsolate;
//
// ,
//
//
void callerCreateIsolate() async {
//
// ReceivePort
// SendPort
//
ReceivePort receivePort = ReceivePort();
//
//
//
newIsolate = await Isolate.spawn(
callbackFunction,
receivePort.sendPort,
);
//
// ""
//
newIsolateSendPort = await receivePort.first;
}
//
//
//
static void callbackFunction(SendPort callerSendPort){
//
// SendPort
// ""
//
ReceivePort newIsolateReceivePort = ReceivePort();
//
// "" SendPort
//
callerSendPort.send(newIsolateReceivePort.sendPort);
//
//
//
}
:
1.2. 2:
,
, :
//
// ,
//
//
// ""
// String ( )
//
Future<String> sendReceive(String messageToBeSent) async {
//
//
//
ReceivePort port = ReceivePort();
//
// ,
// ,
//
//
newIsolateSendPort.send(
CrossIsolatesMessage<String>(
sender: port.sendPort,
message: messageToBeSent,
)
);
//
//
//
return port.first;
}
//
// Callback-
//
static void callbackFunction(SendPort callerSendPort){
//
// SendPort
//
//
ReceivePort newIsolateReceivePort = ReceivePort();
//
// "" SendPort
//
callerSendPort.send(newIsolateReceivePort.sendPort);
//
// , ,
//
//
newIsolateReceivePort.listen((dynamic message){
CrossIsolatesMessage incomingMessage = message as CrossIsolatesMessage;
//
//
//
String newMessage = "complemented string " + incomingMessage.message;
//
//
//
incomingMessage.sender.send(newMessage);
});
}
//
//
//
class CrossIsolatesMessage<T> {
final SendPort sender;
final T message;
CrossIsolatesMessage({
@required this.sender,
this.message,
});
}
1.3. 3:
, :
void dispose(){
newIsolate?.kill(priority: Isolate.immediate);
newIsolate = null;
}
1.4. — Stream
, ""
"" (Streams). Single-Listener Stream
( ).
2. (One-shot computation)
,
, Dart
compute
,
: ( ).
3.
, ,
(Platform-Channel communication)
(main isolate).
, .
,
,
.
Future
, :
, (user experiences lags), .
, :
- ,
( ) - ,
, — Event Loop
Futures
- ,
, —
, , , Futures
( async
-) — Futures
Event Loop
"" . , ( - , ).
, Future
— , .
:
- JSON, (HttpRequest),
=> compute
- : =>
- ( ..) =>
- :
, , .
, , Event Loop
.
Es ist auch wichtig, nicht zu vergessen, dass Flutter
( Dart
) Single-Threaded ist. Um die Benutzer zufrieden zu stellen, müssen Entwickler sicherstellen, dass die Anwendung so reibungslos wie möglich funktioniert. Futures
und
- leistungsstarke Tools zur Erreichung dieses Ziels.
Viel GlĂĽck