Verschiedene Möglichkeiten zum asynchronen Zurückgeben einer Sammlung (mit C # 7-Funktionen)

9

Ich habe eine einfache synchrone Methode, die so aussieht:

%Vor%

Da die Methode Teil einer Webanwendung ist, ist es sinnvoll, alle Ressourcen so effektiv wie möglich zu nutzen. Daher möchte ich die Methode in eine asynchrone ändern. Die einfachste Möglichkeit ist, etwas wie folgt zu tun:

%Vor%

Ich bin kein Experte in async / await oder IEnumerable . Wie ich jedoch verstehe, "verbraucht" die Verwendung dieses Ansatzes die Vorteile von IEnumerable , weil die Aufgabe erwartet wird, bis die gesamte Sammlung geladen ist, wodurch die "Faulheit" der Sammlung IEnumerable wegfällt.

In anderen StackOverflow-Posts habe ich mehrere Vorschläge zur Verwendung von Rx.NET (oder System.Reactive) gelesen. Beim schnellen Durchsuchen der Dokumentation habe ich gelesen, dass IObservable<T> ihre asynchrone Alternative zu IEnumerable<T> ist. Die naive Methode zu verwenden und zu versuchen, Folgendes einzugeben, funktionierte jedoch nicht:

%Vor%

Ich habe einen Kompilierungsfehler, dass IObservable<T> weder GetEnumerator() , noch GetAwaiter() implementiert - somit kann nicht yield und async verwendet werden. Ich habe die Dokumentation von Rx.NET nicht tiefer gelesen, daher benutze ich die Bibliothek wahrscheinlich nur falsch. Aber ich wollte keine Zeit damit verbringen, ein neues Framework zu lernen, um eine einzelne Methode zu modifizieren.

Mit den neuen Möglichkeiten in C # 7 es ist jetzt möglich, benutzerdefinierte Typen zu implementieren. Somit könnte ich theoretisch eine IAsyncEnumerable implementieren, die sowohl GetEnumerator() als auch GetAwaiter() Methoden definieren würde. Aus meiner vorherigen Erfahrung erinnere ich mich jedoch an einen erfolglosen Versuch, eine benutzerdefinierte Implementierung von GetEnumerator() zu erstellen ... Ich landete mit einer einfachen Liste, versteckt in einem Container.

Somit haben wir 4 mögliche Ansätze, um die Aufgabe zu lösen:

  1. Behalte den Code synchron, aber mit IEnumerable
  2. Ändere es in asynchron, aber wende IEnumerable in einem Task<T>
  3. Lerne und verwende Rx.NET (System.Reactive)
  4. Erstellen Sie eine benutzerdefinierte IAsyncEnumerable mit C # 7-Funktionen

Was sind die Vor- und Nachteile jedes dieser Versuche? Welche davon hat den größten Einfluss auf die Ressourcennutzung?

    
lss 28.08.2017, 14:27
quelle

1 Antwort

2
  
  • Halten Sie den Code synchron, aber mit IEnumerable
  •   
  • Ändern Sie es in asynchron, aber wickeln Sie IEnumerable in eine Aufgabe
  • ein   
  • Lerne und verwende Rx.NET (System.Reactive)
  •   
  • Erstellen Sie ein benutzerdefiniertes IAsyncEnumerable mit C # 7-Features
  •   

Was sind die Vor- und Nachteile jedes dieser Versuche? Welche   von ihnen hat den größten Einfluss auf die Ressourcennutzung?

In Ihrer Situation klingt es wie die beste Option ist Task<IEnumerable<T>> . Hier ist, was jede Option auszeichnet:

  1. Synchroner Code (oder paralleler synchroner Code) zeichnet sich aus, wenn keine E / A, aber eine hohe CPU-Auslastung vorhanden ist. Wenn der E / A-Code synchron abläuft (wie bei der ersten Methodenimplementierung), zündet die CPU nur Zyklen, während sie darauf wartet, dass der Webdienst reagiert und nichts tut.

  2. Task<IEnumerable<T>> ist für den Fall vorgesehen, dass eine E / A-Operation eine Sammlung abruft. Der Thread, der auf die E / A-Operation wartet, kann dann noch etwas anderes auf ihn warten lassen. Das klingt nach deinem Fall.

  3. Rx eignet sich am besten für Push-Szenarien: Wo Daten an Ihren Code "gepusht" werden, auf den Sie antworten möchten. Übliche Beispiele sind Anwendungen, die Börsenkursdaten oder Chat-Anwendungen erhalten.

  4. IAsyncEnumerable ist für eine Sammlung gedacht, bei der jedes Element eine asynchrone Aufgabe erfordert oder generiert. Ein Beispiel: Iterieren über eine Sammlung von Elementen und Ausführen einer Art eindeutiger DB-Abfrage für jede einzelne. Wenn Ihre Transform tatsächlich eine I / O-gebundene asynchrone Methode ist, dann ist dies wahrscheinlich sinnvoller.

Shlomo 28.08.2017, 15:13
quelle