wake-up-neo.com

Anwendungsfälle für RxJava-Scheduler

In RxJava gibt es 5 verschiedene Scheduler zur Auswahl:

  1. instant () : Erstellt einen Scheduler und gibt diesen zurück, der die Arbeit am aktuellen Thread sofort ausführt.

  2. trampoline () : Erstellt einen Scheduler und gibt diesen zurück, der die Arbeit an dem aktuellen Thread in die Warteschlange stellt, die ausgeführt werden soll, nachdem die aktuelle Arbeit abgeschlossen ist.

  3. newThread () : Erstellt einen Scheduler und gibt diesen zurück, der für jede Arbeitseinheit einen neuen Thread erstellt.

  4. computation () : Erstellt einen Scheduler für die Rechenarbeit und gibt diesen zurück. Dies kann für Ereignisschleifen, die Verarbeitung von Rückrufen und andere Berechnungsarbeiten verwendet werden. Führen Sie keine E/A-gebundenen Arbeiten an diesem Scheduler durch. Verwenden Sie stattdessen Scheduler. io () .

  5. io () : Erstellt einen Scheduler für E/A-gebundene Arbeit und gibt diesen zurück. Die Implementierung wird durch einen Executor-Thread-Pool unterstützt, der bei Bedarf erweitert wird. Dies kann für die asynchrone Ausführung von E/A-Blockierungen verwendet werden. Führen Sie keine Berechnungen mit diesem Scheduler durch. Verwenden Sie stattdessen Scheduler. computation () .

Fragen:

Die ersten 3 Scheduler sind ziemlich selbsterklärend; Ich bin jedoch ein wenig verwirrt über Berechnung und io .

  1. Was genau ist "IO-gebundene Arbeit"? Wird es für den Umgang mit Streams verwendet (Java.io) und Dateien (Java.nio.files)? Wird es für Datenbankabfragen verwendet? Wird es zum Herunterladen von Dateien oder für den Zugriff auf REST APIs verwendet?
  2. Inwiefern unterscheidet sich computation () von newThread () ? Befinden sich alle computation () Aufrufe jedes Mal in einem einzelnen (Hintergrund-) Thread anstelle eines neuen (Hintergrund-) Threads?
  3. Warum ist es schlecht computation () aufzurufen, wenn Sie IO arbeiten?
  4. Warum ist es schlecht, bei der Rechenarbeit io () aufzurufen?
241
bcorso

Tolle Fragen, ich denke die Dokumentation könnte etwas detaillierter sein.

  1. io() wird von einem unbegrenzten Thread-Pool unterstützt und ist die Art von Dingen, die Sie für nicht rechenintensive Aufgaben verwenden würden, dh Dinge, die die CPU nicht stark belasten. Die Interaktion mit dem Dateisystem, die Interaktion mit Datenbanken oder Diensten auf einem anderen Host sind also gute Beispiele.
  2. computation() wird von einem begrenzten Thread-Pool mit der Größe der Anzahl der verfügbaren Prozessoren unterstützt. Wenn Sie versucht haben, eine CPU-intensive Arbeit parallel auf mehr als den verfügbaren Prozessoren zu planen (z. B. mithilfe von newThread()), stehen Sie vor einem Thread-Erstellungs-Overhead und einem Kontextwechsel-Overhead, da Threads für einen Prozessor in Frage kommen und dieser möglicherweise sehr umfangreich ist Leistungstreffer.
  3. Es ist am besten, computation() für die CPU-intensive Arbeit zu belassen, da Sie sonst keine gute CPU-Auslastung erhalten.
  4. Es ist schlecht, io() für Berechnungsarbeiten aus dem in 2 erläuterten Grund aufzurufen. io() ist nicht beschränkt, und wenn Sie tausend Berechnungsaufgaben für io() parallel planen, dann jede Von diesen tausend Aufgaben hat jede einen eigenen Thread und konkurriert um die CPU, die mit Kosten für den Kontextwechsel verbunden ist.
317
Dave Moten

Dieser Blog-Beitrag bietet eine hervorragende Antwort

Aus dem Blogbeitrag:

Schedulers.io () wird von einem unbegrenzten Thread-Pool unterstützt. Es wird für nicht CPU-intensive E/A-Arbeiten verwendet, einschließlich Interaktion mit dem Dateisystem, Ausführen von Netzwerkaufrufen, Datenbankinteraktionen usw. Dieser Thread-Pool ist für die asynchrone Ausführung von blockierenden E/A vorgesehen.

Schedulers.computation () wird von einem begrenzten Thread-Pool mit einer Größe bis zur Anzahl der verfügbaren Prozessoren unterstützt. Es wird für rechen- oder rechenintensive Arbeiten verwendet, z. B. zum Ändern der Größe von Bildern, zum Verarbeiten großer Datenmengen usw. Seien Sie vorsichtig: Wenn Sie mehr Rechenthreads als verfügbare Kerne zuweisen, wird die Leistung aufgrund von Kontextumschaltungen und Mehraufwand bei der Thread-Erstellung beeinträchtigt Prozessorzeit.

Schedulers.newThread () erstellt einen neuen Thread für jede geplante Arbeitseinheit. Dieser Scheduler ist teuer, da jedes Mal ein neuer Thread erzeugt wird und keine Wiederverwendung stattfindet.

Schedulers.from (Executor Executor) erstellt einen benutzerdefinierten Scheduler und gibt diesen zurück, der vom angegebenen Executor unterstützt wird. Verwenden Sie Scheduler.from (Executors.newFixedThreadPool (n)), um die Anzahl der gleichzeitigen Threads im Threadpool zu begrenzen. Dies garantiert, dass eine geplante Aufgabe, wenn alle Threads belegt sind, in die Warteschlange gestellt wird. Die Threads im Pool bleiben bestehen, bis sie explizit heruntergefahren werden.

Haupt-Thread oder AndroidSchedulers.mainThread () wird von der RxAndroid-Erweiterungsbibliothek für RxJava bereitgestellt. Im Hauptthread (auch als UI-Thread bezeichnet) findet die Benutzerinteraktion statt. Es sollte darauf geachtet werden, diesen Thread nicht zu überlasten, um zu verhindern, dass die Benutzeroberfläche oder, schlimmer noch, das Dialogfeld "Anwendung antwortet nicht" (Application Not Responding, ANR) nicht reagiert.

Schedulers.single () ist neu in RxJava 2. Dieser Scheduler wird von einem einzelnen Thread unterstützt, der Tasks nacheinander in der angeforderten Reihenfolge ausführt.

Schedulers.trampoline () führt Aufgaben auf eine FIFO (First In, First Out) Weise durch einen der Teilnehmer aus Arbeitsthreads: Diese werden häufig bei der Implementierung von Rekursionen verwendet, um das Anwachsen des Aufrufstapels zu vermeiden.

1
joe