Flattern. Asynchronität (asynchron) <> Parallelität (isolieren). Überhaupt

Einführung



Kürzlich war ich überrascht, dass meine Kollegen nicht genau wissen, was Asynchronität in Flutter ist. Aus irgendeinem Grund hatten sie die Idee, dass die asynchrone Funktion, wenn sie korrekt geschrieben ist, die Schnittstelle nicht blockiert. Nachdem ich ein paar Artikel durchgeblättert hatte, fand ich keine einfache, vollständige und klare Erklärung für diese ganze Küche (alles entspricht dem Prinzip - "wähle 2 von 3")). In einem Artikel habe ich sogar gelesen, dass Dart eine wunderbare Asynchronität hat, die es Ihnen ermöglicht, die Codeausführung zu verschieben, bis der Thread freier ist (was meiner Meinung nach etwas irreführend ist) (Hinweis: in den Kommentaren nikita_dolwies darauf hin, was wahrscheinlich bedeutete - ScheduleTask ).



Für wen der Artikel



Der Artikel ist für diejenigen gedacht, die gerade erst anfangen, sich mit Flutter vertraut zu machen. Daher werde ich versuchen, in diesem kleinen Hinweis anhand eines einfachen Beispiels zu zeigen, dass Asynchronität nur die Fähigkeit ist, Code nicht sequentiell auszuführen. Wenn Sie jedoch eine "schwere" Funktion haben (auch wenn diese dreimal asynchron ist), wird die Schnittstelle dennoch für Sie blockiert. Natürlich ist es unwahrscheinlich, dass Sie in einem echten Produkt auf solche offensichtlichen Erscheinungsformen stoßen (im Moment sind die Prozessoren ziemlich leistungsfähig), aber es lohnt sich immer noch zu verstehen, wie es funktioniert.



Gehen



Nehmen wir also ein Beispiel aus der Dokumentation für die Bibliothek flutter_bloc für Experimente . Lassen Sie uns die Funktion "_mapTimerStartedToState" der Klasse "timer_bloc" leicht ändern - kommentieren Sie das Zähler-Update aus, damit es nicht stört:



Stream<TimerState> _mapTimerStartedToState(TimerStarted start) async* {
  yield TimerRunInProgress(start.duration);
  _tickerSubscription?.cancel();
  // _tickerSubscription = _ticker
  //     .tick(ticks: start.duration)
  //     .listen((duration) => add(TimerTicked(duration: duration)));
}

      
      







Fügen wir eine neue statische Funktion hinzu (wir machen es im Voraus so - isolieren funktioniert nur mit ihnen):



static Future<void> _heavyComput (SendPort sendPort) async {
  await Future.delayed(Duration(seconds: 5));

  print('=======================');
  print('!!!function finished!!!');
  print('=======================');
  return null;
}

      
      







Hier warten wir als Nachahmung schwerer Berechnungen auf das Ende der Verzögerung von 5 Sekunden.

Wir ändern die mapEventToState-Funktion - fügen am Ende einen asynchronen Aufruf zu _heavyComput hinzu:



@override
Stream<TimerState> mapEventToState(
  TimerEvent event,
) async* {

. . .
  
  _heavyComput(null);
}

      
      







Für den ersten Test ist alles bereit - unsere Aufgabe ist es, die magischen Wellen zu beobachten.

Wir starten und sehen - die Wellen sind besorgt, die Schnittstelle ist nicht blockiert, die Meldung über das Ende der Funktion wird nach 5 Sekunden angezeigt.







Das ist wunderbare Asynchronität - die Panik war falsch. Hmm ... Was ist, wenn Future.delayed (Dauer (Sekunden: 5)) durch eine Schleife ersetzt wird?



static Future<void> _heavyComput(SendPort sendPort) async {
  int pause = 1200000000;
  for (int i = 0; i < pause; i++) {}
  print('=======================');
  print('!!!function finished!!!');
  print('=======================');
  return null;
}

      
      





Wir starten es und das wars - "angekommen" - die Wellen machen sich keine Sorgen mehr.







Ich denke, hier ist nicht viel Erklärung nötig: Selbst eine asynchrone schwere Funktion blockiert alles. Standardmäßig wird der gesamte Code in einem Thread ausgeführt. Es ist nur so, dass im ersten Fall keine Berechnungen erforderlich waren, sondern nur gewartet werden musste, und im zweiten Fall waren Berechnungen erforderlich.



Nun, und damit sich der Artikel nicht als vollständig mikroskopisch herausstellt, rufen wir diese Funktion mit isolate auf. Ändern wir den mapEventToState:



@override
Stream<TimerState> mapEventToState(
  TimerEvent event,
) async* {
. . .
  var _receivePort = ReceivePort();
  var _isolate = Isolate.spawn(_heavyComput, _receivePort.sendPort);
}

      
      







Wir starten es und stellen fest, dass die Schnittstelle nicht blockiert ist. Wir erhalten eine Nachricht über den Abschluss der Funktion mit einer merklichen Verzögerung.







Das ist alles (wie asynchron und auf Arbeit warten - es gibt viele Artikel, ich denke, Sie sollten hier nicht aufhören).



Ein Beispiel kann unter dem Link flutter_timer_async_and_parallels heruntergeladen werden



All Articles