Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Erstellen einer entsprechenden sync Funktion für eine async Funktion (oder besser andersherum?)
MysticEmpires
myCSharp.de - Member



Dabei seit:
Beiträge: 303

Themenstarter:

Erstellen einer entsprechenden sync Funktion für eine async Funktion (oder besser andersherum?)

beantworten | zitieren | melden

Hi,

mal ne kleine Frage. Ich schreibe gerade eine library. Diese hat auch einige Async Funktionen. Jedoch wollte ich nach .net Vorbild auch einen passenden synchrone-Funktion anbieten. Bis jetzt mache ich das wie folgt:

private String Test()
{
    return TestAsync().Result;
}

private async Task<String> TestAsync()
{
    await Task.Delay(5000);

    return "sdfsdf";
}

Das Funktioniert soweit auch. Jedoch habe ich mich gefragt ob es für diesen Fall nicht einen "best practice" gibt. Wie macht ihr das?

Gruß
Mystic
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von MysticEmpires am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15963

beantworten | zitieren | melden

Prinzipiell erstelle ich nur synchrone Methoden und optional asynchrone Methoden. Das ist auch der Weg von .NET - nicht umgekehrt.

Die asynchronen implementier ich entweder sauber mit an die entsprechende Stelle (zB DB Providern, die Async vollständig unterstützen), oder ich nehme die TPL als Hilfe:
Siehe Methode Task<IEnumerable<string>> EnumerateDirectoryPathsAsync

Dahinter steckt dann

      public static Task<T> GetAsyncResult<T>( Func<T> action )
            {
                var tcs = new TaskCompletionSource<T>( );

                AsyncTaskFactory.StartNew( ( ) =>
                {
                    try
                    {
                        tcs.SetResult( action( ) );
                    }
                    catch ( Exception ex )
                    {
                        tcs.SetException( ex );
                    }
                } );

                return tcs.Task;
            }

Von TPL auf async hart runter zu brechen ist Dein Weg schon ok so.
Wenn Deine Async aber eigentlich nur was stupides macht, dann implementier es als synchron und biete das async optional wie in meinem Beispiel an.
Ansonsten wird Dir immer ein Overhead aufgezwungen was nicht sinnvoll ist.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
MysticEmpires
myCSharp.de - Member



Dabei seit:
Beiträge: 303

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Prinzipiell erstelle ich nur synchrone Methoden und optional asynchrone Methoden. Das ist auch der Weg von .NET - nicht umgekehrt.

Ich habe mal nachgesehen. Stimmt .net macht es genauso:

referencesource.microsoft.com: DBConnection.cs, Methode OpenAsync
Zitat von Abt
Ansonsten wird Dir immer ein Overhead aufgezwungen was nicht sinnvoll ist.

Stimmt sonst würde er ja beim Synchronen Aufruf die ganze TPL mit schleifen obwohl das total unnötig ist.

Also fassen wir zusammen. Komplett in TPL schreiben und dann runter brechen ist ok sofern der Code auch komplett async unterstützt. Sonst sollte man normal sync schreiben und async anbieten über entsprechende pattern.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von MysticEmpires am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15963

beantworten | zitieren | melden

Interessant. Wusste gar nicht, dass das hier genauso umgesetzt ist.
Einige DB Provider unterstützen nämlich auch den kompletten asynchronen Prozess bis zur Datenbank selbst.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
MysticEmpires
myCSharp.de - Member



Dabei seit:
Beiträge: 303

Themenstarter:

beantworten | zitieren | melden

Ja andere Async Funktionen sind auch wesentlich komplexer aufgebaut. Den "CancellationToken"-Part kannst ja bei deinen Funktionen nocht erweitern :)

Wieso hast du eigentlich in deiner "ExecuteAsync" den Part für SetException nicht mit rein genommen? Vom Prinzip kannst es da ja so machen wie im.net result auf "null" setzen und action einfach ausführen. Und wieso hast du extra einen Variable für Task.Factory angelegt?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MysticEmpires am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15963

beantworten | zitieren | melden

ExecuteAsync ist für mich nur ein ShortCut einen Task zu erstellen (und dabei optional eben einen eigenen/speziellen Scheduler zu nutzen).
Im Prinzip wie Task.Run in .NET 4.5 nur will ich eben mehrere .NET Versionen möglichst einfach Unterstützen (und variabel im Sinne des Schedulers bleiben).
In den oberen beiden Methoden ExecuteAsyncResult und GetAsyncResult hab ichs ja drin.

PS für die anderen. Es geht um die Klasse QuickIO.Compatibilits.NETCompatbility.cs

Das Klassenfeld AsyncTaskFactory ist ein Platzhalter falls ich mal doch auf die Idee komm eine eigene Factory zur Verfügung zu stellen bzw. die Möglichkeit anbiete eine eigene Factory bereit zu stellen.

Standardmäßig wird von Task.Factory eben der ThreadPool verwendet; aber man kann ja auch einen eigenen Implementieren.
Siehe dazu auch ParallelExtensionsExtras Tour - #7 - Additional TaskSchedulers
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
malignate
myCSharp.de - Member

Avatar #avatar-3206.png


Dabei seit:
Beiträge: 751

beantworten | zitieren | melden

Ich muss das einfach noch mal wiederholen, weil das so oft falsch gemacht wird:

Man muss hier zwischen Asynchronität und Parallelität unterscheiden.

1. Async: Asynchroner Code ist IO-Bound und delegiert die Aufgabe an einen externe Ausführungseinheit, z.B. Hardware, einen anderen Prozess oder ein komplett anderes System und fahrt dann mit der Ausführung der eigenen Antwort fort, ohne, sobald das Ergebnis da ist. Das hat den Vorteil, dass der aktuelle Thread nicht blockiert wird, der dann gleichzeitig andere Dinge erledigen kann:
- In einer Desktop-Anwendung blockiert die UI nicht, der UI-Thread kann weiter Animationen ablaufen lassen und auf Interaktion reagieren.
- In einer Server-Anwendung kann der Thread weitere Requests entgegen nehmen, bis er auf die asynchrone Antwort reagieren muss.

2. Parallel: Paraleller Code erstellt neue Threads um CPU-lastige Algorithmen zu beschleunigen oder Dinge nebenläufig auszuführen.

Auf Basis dieser Definitionen würde ich folgende Best-Practices:

1. Wenn du etwas IO-lastiges hast, implementiere zuerst die asynchrone Methode und schreibe dann darauf aufbauen eine synchrone Methode, wie du es gemacht hast. Du kannst aus einer synchronen Methode keine asynchrone Methoden machen, sondern nur eine parallele.

2. Schreibst du ein Framework, verwende Tasks nur dann, wenn du einen CPU-lastigen Algorithmus wesentlich beschleunigen kannst, z.B. ein Sortierungalgorithmus. Es ist keine gute Idee, eine Task-Wrapper-Methdode für eine synchrone Methoden anzubieten, weil die Methode dann asynchron aussieht, obwohl sie es gar nicht ist. Außerdem ist der Overhead je nachdem riesig.

3. Verwende keine parallen Task in Server-Anwendung, es sei denn du bist dir wirklich sicher. Es blockiert Thread, die bessere Antwortzeit geht auf Kosten de Skalierbarkeit.

@Abt: Diese Directory-Methoden sind meiner Meinung nach eine üble Idee, das gaukelt Asynchronität vor, die gar nicht vorhanden ist.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo malignate,

grundsätzlich scheint sich das Netz einzig zu sein, dass es einen Unterschied zwischen asynchron und parallel gibt. Allerdings scheint es wohl keine allgemein anerkannte, präzise Definition der beiden Begriffe zu geben und jeder sieht es im Detail doch etwas anders.

Aus meiner Sicht ist es z.B. vollkommen egal, ob für Parallelität neue oder bestehende Threads (z.B. aus dem ThreadPool) verwendet werden, solange eine echt gleichzeitige Ausführung erfolgt. Andersherum kann Asynchronität durchaus durch ein paralleles Konstrukt (z.B. das Erstellen eines neuen Threads) erreicht werden.

Auch würde ich den Unterschied zwischen Asynchronität und Parallelität keineswegs nur an IO-bound oder CPU-lastig festmachen. Klar, wenn ein Thread wegen IO blockiert ist, wird er nicht mehr parallel zu anderen Threads ausgeführt, denn er wird gar nicht ausgeführt, sondern ist gerade blockiert. Aber auch eigentlich CPU-lastige Threads können z.B. wegen der Synchronisation eines Zugriffs auf eine gemeinsame Ressource gerade blockiert sein und damit gerade nicht parallel ausgeführt werden. Andersherum kann aber eine CPU-lastige Aufgabe durchaus asynchron zum Haupt-Thread ausgeführt werden.

Und zu guter Letzt bedeutet eine nebenläufige Ausführung nicht automatisch auch, dass sie (echt) parallel erfolgt. Schon eine (präemptiv) verzahnte Ausführung ist nebenläufig, aber gerade nicht parallel.

zu 1. Wenn das APIs des Betriebssystems nur synchrones IO unterstützt, dann ist es vollkommen ok, in der eigenen Klasse eine darauf basierende synchrone Methode anzubieten und auf dieser basierend eine asynchrone Methode, die natürlich durch Verwendung eines parallelen Konstrukts (z.B. eines neuen Threads oder eines freien ThreadPool-Thread, je nach Geschmack auch gekapselt als Task) erreicht werden kann.

Richtig ist aber, dass wenn das APIs des Betriebssystems asynchrones IO unterstützt, dass man dies in der eigenen Klasse als Basis verwenden sollte und die eigene synchrone auf der eigenen asynchronen Methode aufbauen sollte. Sonst würde man unsinnigerweise das asynchrone API erst synchron zwingen, um dann wieder für die asynchrone Methode die Asynchronität mit zusätzlichen Mitteln realisieren zu müssen.

Die Frage ist also weniger, ob die Aufgabe IO-bound oder CPU-lastig ist, sondern ob die Basis, auf die man sich stützt, bereits asynchron ist oder nicht.

zu 2. Tasks haben ihre Berechtigung nicht nur bei CPU-lastigen Aufgaben, sondern sind ein generell einsetzbares Konstrukt.

Asynchronität kann man m.E. nicht vorgaukeln. Eine Methode, die sofort zurückkehrt, aber das Resultat erst "nachträglich" liefert, ist asynchron. Egal, ob sie intern auf einem asynchronen API basiert oder die Asynchronität durch Verwendung eines parallelen Konstrukts realisiert.

herbivore
private Nachricht | Beiträge des Benutzers
malignate
myCSharp.de - Member

Avatar #avatar-3206.png


Dabei seit:
Beiträge: 751

beantworten | zitieren | melden

Hallo herbivore,

es ist wichtig, dass es hier um eine eigene Library geht, meine Pauschalisierung trifft für Anwendungen nicht zu.

Ich finde die Unterscheidung zwischen Asynchronität und Parallelität auch extrem schwierig, vielleicht ist es im Englischen besser, aber im Deutschen klingt beides ziemlich gleich, nämlich, dass ich irgendwas nebenläufig mache. Deshalb versuche ich mal eine andere Definition mit neuen Begriffen, weil die deutlicher macht, was man erreichen möchte:

1. Externe Nebenläufigkeit werden verwendet, wenn man eine Aufgabe an ein anderes System delegiert, Beispiele dafür:

- Ein anderer Server führt eine Anfrage aus
- Ein anderer Prozess bearbeitet meine Anfrage
- Die Datenbank führt eine Abfrage aus
- Das IO-System liest einen Block von der Festplatte

2. Interne nebenläufige Methoden behalten die Kontrolle und führen Dinge parallel aus. Das muss nicht nur CPU-lastig sein, sondern kann natürlich auch IO-Anfragen enthalten. Hier sind die Anteile aber extrem wichtig. Wenn man beispielsweise 10 parallele Anfragen an einen externen Server hat und vor jeder Anfrage Berechnungen mit 1ms ausführt, sollte man sich zweimal überlegen, ob man nicht lieber ohne Thread-Parallelität, sondern mit asynchronen Methoden arbeitet.

Allgemein ist async-await ja nur ein schönerer Synchronizationsmechanismus für Callbacks, das Problem ist aber, dass typischerweise asynchrone Methoden für externe Nebenläufigkeit verwendet werden. Wenn mir jetzt jemand in einer API eine asynchrone Methode bietet, gehe ich auch davon aus. Verwende ich diese Methode mit falschen Annahmen kann ich genau das Gegenteil erreichen, was ich erreichen möchte, z.B. in Server-Anwendungen die unnötige Belegung von Threads und schlechtere Skalierbarkeit. Deshalb finde ich es eine schlechte Idee in APIs synchrone Methoden zu Wrappen. Wenn ich irgendwo Nebenläufigkeit brauche, sollte man es außerhalb der API machen, hier kann ich dann auch innerhalb eines Tasks mehrere synchrone IO-Methoden aneinander hängen.
Es hält mich natürlich nichts davon ab, zur Performance-Optimierung Tasks zu verwenden, (beispiel Sortierung), dann ist die Methode aber nach außen weiterhin synchron.

Deshalb hier meine Regel in der Kurzfassung: Stelle in APIs nur Async-Methoden für externe Nebenläufigkeit bereit.

Die Verwendung von async und Tasks in einer Anwendung ist natürlich abhängig von der Situation.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von malignate am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo malignate,

grundsätzlich kann ich deinen Einwand verstehen, dass das Wrapen einer synchronen Bibliotheksmethode durch eine asynchrone unter Verwendung von Threads oder Tasks zu einer unnötigen Belegung von Threads und möglicherweise zu einer schlechteren Skalierbarkeit führen kann.

Und ich bin ohne kein Freund davon, dass es in WinRT die Vorgabe gibt, dass alle (Bibliotheks-)Methoden, die potenziell mehr als 50ms Ausführungszeit benötigen, asynchron arbeiten sollen/müssen. Der Hintergrund ist dieser Forderung ist, dass es zu kleiner Blockierung des GUIs durch langlaufende Methode kommt. Ich finde jedoch, es gehört in die Zuständigkeit des Programmierers des GUIs dessen Blockierung mit geeigneten Mitteln zu verhindern. Es ist nicht die Aufgabe des Programmierers der Bibliothek, prophylaktisch Asynchronität in jede einzelnen langlaufende Bibliotheksfunktion einzubauen. Zumal gar nicht klar ist, ob die Bibliotheksfunktionen überhaupt aus dem GUI-Thread benutzt werden. Zur Frage der Zuständigkeiten habe ich schon früher geschrieben, siehe Eleganteste Art aus Worker-Thread auf Controls zugreifen [generell Kontrollfluss zwischen Threads].

Insofern muss es, wenn es nach mir geht, auch keinen asynchronen Wrapper für eine synchrone Methode geben. Ich würde es dem Aufrufer der synchronen (Bibliotheks-)Methode überlassen, ob er diese direkt synchron oder mit eigenen Mitteln asynchron ausführt.

Allerdings könnte ich verstehen, wenn der Ersteller einer Bibliothek aus Komfortgründen einen asynchronen Wrapper anbieten möchte. Es ist dann ja die Entscheidung des Aufrufers, ob er die synchrone Methode oder den asynchronen Wrapper verwenden möchte. Wenn der Aufrufer eine unnötigen Belegung von Threads verhindern will, hat er durch die Verwendung der synchronen Methode die volle Kontrolle, wie er eine ggf. benötigte Asynchronität selbst herstellen will.

Insofern würde ich asynchrone Wrapper nicht per se verteufeln, wenn man deinen Einwand im Hinterkopf behält und sich nicht blind auf den Wrapper verlässt.

herbivore
private Nachricht | Beiträge des Benutzers
malignate
myCSharp.de - Member

Avatar #avatar-3206.png


Dabei seit:
Beiträge: 751

beantworten | zitieren | melden

Ich würde so einen Wrapper sogar selber verwenden, zum Beispiel in einer Desktop-Anwendung, das Problem ist, dass ich ja von außen nicht unterscheiden, kann, wie die Methode intern arbeitet. Deshalb würde ich mich an die "Konvention" halten (die ich bisher im .NET Framework und anderen Bibliotheken so sehe), dass Async-Methoden "Task XXXAsync(...)" für externe Nebenläufigkeit sind. Ich habe nichts dagegen, wenn jemand Wrapper anbietet, aber dann sollte man die auch irgendwie anderst nennen.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15963

beantworten | zitieren | melden

Zitat von malignate
@Abt: Diese Directory-Methoden sind meiner Meinung nach eine üble Idee, das gaukelt Asynchronität vor, die gar nicht vorhanden ist.
Wir hatten uns ja schon mal beim Thema MongoDB deswegen unterhalten und ich muss sagen ich seh das eben anders als Du.

Es ist durchaus gebräuchlich, dass diese Art und Weise, die ich in den Enumerate-Methoden für einen asynchronen Verlauf, verwendet wird, WENN die darunterliegende API KEIN direktes, asynchrones Verhalten anbietet.
Das zeigen ja auch die .NET eigenen Implementierungen.

Wenn ein Konsument meiner Bibliothek eine Enumeration asynchron aufrufen möchte. Was würde er tun?
Im Prinzip genau das, was ich in meinen Async-Methoden implementiert habe. Und hey.. wenn er das selbst umsetzen will: was hindert ihn daran meine Async-Variante zu vermeiden und selbst eine Erweiterung zu schreiben?
Das hat auch relativ wenig bis gar nichts mit Parallelität zutun, da Parallelität und lokale Festplatten ohne RAID eine ziemlich doofe Idee sind.

Ich möchte Dich hier auch kurz an Deinen eigenen Forderungen aufhängen, denn Du machst es selbst nicht besser:
Zitat
Man muss hier zwischen Asynchronität und Parallelität unterscheiden.
Genau. Und meine Methoden sind asynchron und nicht parallel. Deswegen heißen sie Async und nicht AsParallel.
Nur weil man einen Task benutzt heisst das nicht, dass es parallel ist.
Es wird hier eine einzeln Aufgabe ausgelagert (sie wird extern), damit zB die GUI nicht hängen bleibt. Wie würdest Du eine lang-dauernde, synchrone Methode denn sonst umsetzen, damit die GUI nicht hängt?
Korrekt: [FAQ] Warum blockiert mein GUI?
Und wie sieht die Innerei aus? GENAU wie meine Async-Methoden. Genau das ist es auch: es ist ein asynchrones Verhalten.

Egal wo letzten Endes Async aufschlägt: es wird ein Callback erzeugt und ein Task/Thread, der darauf wartet. Wo das nun ist spielt für den Verlauf eigentlich Rolle, da das Verhalten beim Konsumieren der Methode absolut identisch ist.
Alternativ gibts eben ein Fire-and-forget-Verhalten und eine Zweit-Methode die ähnlich wie Events arbeitet, was aber selbst bei großen Produkten nicht ganz so oft vor kommt wie Du denkst.

Wenn Du aber - trotz Asynchronität - auf das Ergebnis des Callbacks wartest. Wie machst Du das?
Normalerweise mit einem Task, der auf ein Flag o.ä. wartet. Was hast Du hier nun gewonnen? Korrekt: nichts.

Der Overhead bei meinen Implementierungen sind selbst in der Messung verschwindend gering, sodass man sie absolut vernachlässigen kann.
Ich habe auch mit MongoDB und meinen Async-Methoden absolut mehr Vorteile als Nachteile.

Ich kann leider Deiner Argumentation in diesem Fall absolut nicht teilen; denn zB das Thema Sortierung und Parallelität, das Du ansprichst, ist in der Regel kontraproduktiv für das Sortieren.
Zitat
Verwende keine parallen Task in Server-Anwendung, es sei denn du bist dir wirklich sicher. Es blockiert Thread, die bessere Antwortzeit geht auf Kosten de Skalierbarkeit.
Das war mal so, dass man in IIS Anwendungen kein ThreadPool verwenden soll aber das ist nach einem KB schon laaange Geschichte.
Ich kenne zB kaum ein Azure-Tutorial von MS, das kein Task oder Async verwendet, wenn es mit ServiceBus oder WorkerRoles kommuniziert.

IO-lastig ist auch nicht gleich IO-lastig. Du musst Differenzieren, WAS der IO ist.
Generell kann ich also leider Deine Meinung hier absolut nicht teilen.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
malignate
myCSharp.de - Member

Avatar #avatar-3206.png


Dabei seit:
Beiträge: 751

beantworten | zitieren | melden

Hallo Abt,

das sind so viele einzelne Themen, deshalb Liste ich hier meine Anworten einfach mal auf:

@Skalierung: Du hast absolut recht, es kommt auf das Szenario an, ich mache aber mal ein Beispiel: Bei Busliniensuche machen wir tlw. bis zu 50 externe Requests pro Suchanfrage, die im Mittel vll. 250ms dauern. Die Anzahl Threads pro Core sind im IIS 50, bei einem QuadCore hätte ich also 200 Threads zur Verfügung. Würde ich die Aufrufe mit einem Task-Wrapper parallel durchführen könnte ich pro Sekunde nur 15 Suchanfragen durchführen, mit einer asynchronen Implementierung, welche die asynchronen Http-Methoden nutzt bin ich nur durch meine Netzwerkanbindung, die externe Resource und die Anzahl der Http-Verbindungen begrenzt, die das Betriebssystem erstellen kann. Ein Extrem-Beispiel ist hier Node.js, da meines Wissens nach Node Single-Threaded ist und die Skalierung alleine durch "echte" Asynchronität erreicht wird.

@Azure-Tutorial: Async und Tasks haben doch keinen direkten Zusammenhang mit Thread-Pools, ich würde 20€ darauf wetten, dass die Client-Methoden für Queues und so weiter intern die asynchronen Http-Methoden verwenden.

@Framework: Ich habe gestern noch genauer nachgeschaut und ich konnte kaum Beispiele für solche Wrapper im Framework finden. Insbesonder auch nur dann, wo Interfaces oder abstrakte Klassen implementiert werden müssen, z.B. MemoryStream oder StringReader.

@Sortierung: Das ist nicht korrekt, man kann bei großen Datenmengen mit Parallelität durch Tasks sehr gut eine Performance-Verbesserung erreichen, die mit der Anzahl an Prozessoren steigt. ich weiß gar nicht mehr, wie viele Implementierungen für 1D und 2D-Sortierungen ich während des Studiums mit Java und C# gemacht habe und damit immer die Standard-Implementierungen deutlich geschlagen.

@MongoDb: Es kommt ja auf die Anzahl der parallelen Anfagen pro User-Request an und darauf wieviele Millisekunden eien Anfrage dauert. Da wahrscheinlich ein Query nur 20 oder 30ms dauert und du nicht 200 parallele Anfragen pro Benutzer machst, kann ich mir gut vorstellen, dass du von einem Wrapper profitierst. Das trifft aber nicht auf jedes Szenario zu, weshalb es keine gute Idee wäre, die Wrapper in den Mongo-Treiber zu packen. (Ein solcher Vorschlag wurde ja auch schon im Mongo-Jira gemacht).

Wie in meiner letzten Antwort gesagt: Ich habe nichts generell gegen Wrapper-Methoden. Da aber je nach Szenario die Implementierung extrem wichtig ist und ich ja von außen nicht erkenne, wie sie funktioniert, sollte man vll. über eine differenziertere Namensgebung nachdenken. Das wird umso wichtiger, wenn die Ausführungszeit der Methode steigt.

BTW: Ich würde im Zusammenhang mit Asynchronität nicht von Warten reden. Da wartet nämlich niemand, das ist nämlich genau der wichtige Unterschied. Bei asynchronen Methoden wird der SynchronizationContext verwendet, der nach erfolgreicher Ausführung mehr oder weniger eine Methode mit dem Code zur weiteren Ausführung in die Dispatcher-Queue einreiht, die dann von der Programmhauptschleife ausgeführt wird (Desktop) oder in die ThreadPool-Queue (Web).
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von malignate am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15963

beantworten | zitieren | melden

IIS: .NET (3.5) limitiert 250 Thread per CPU; wurde mit 4.0 aber erhöht (auf welche Zahl weiß ich gerade nicht, könnte gut 32767 gewesen sein).
Das Limit des IIS liegt bei 100 pro Core. Wobei das mit unter an ASP liegt nicht am IIS. So wurde mit ASP 4.0 Runtime des RequestsPerCore von 12 auf 5000 erhöht.
Spielt aber auch relativ wenig Rolle da sich viele hundert Tasks einen einzigen Thread teilen (können).
Node.js mit C# zu vergleichen hinkt gewaltig, da Node.js - anders als C#.NET - immer in einer asynchronen Umgebung angewendet wird.

Zum Thema MongoDB und Async: mit der Version 3.0, die dieses Jahr kommt, unterstützt der C# Driver AsycMethoden. Wurde offiziell angekündigt - soviel zum Thema "sinnvoll" ;-)
Dass async auch negative Folgen haben kann aufgrund des Overheads bestreitet doch kein Mensch. Das ist halt so bei einem Kontextwechsel.
Aber es geht hier ja in erster Linie um Methoden, die einige, viele Sekunden Ausführungszeit benötigen. Das spielt ein Overhead von 1/30s keine Rolle.

@Framework/Azure: klar, wenn async bis zum untersten Layer unterstützt wird und es möglich ist, wird es auch verwendet. Aber ist es halt nicht überall.
Trotzdem ermöglicht man mit [FAQ] Warum blockiert mein GUI? ein asynchrones Verhalten.
Und warum wird bitte async mit IO-Bound in einen Topf geworfen? Zwei völlig verschiedene Dinge. Genausowenig wie Tasks in erster Linie nicht mit "Async" oder "Parallel" direkt im Zusammenhang steht, sondern BEIDES gleichermaßen einfach ermöglicht.

Nur weil etwas nicht bis zum untersten Layer asynchron umgesetzt ist heisst das nicht, dass das Gesamtverhalten BEIM KONSUM der Methode nicht asynchron wäre.
Daher ist die Namensgebung in diesem Falle auch völlig korrekt.
Dein eigener Anspruch zu verstehen, was async ist und was nicht, und dass die Tiefe für die Definition keine Rolle spielt, stimmt hier nicht.

Zu Deinem BTW: async/await pattern ist an der Stelle von await, um auf das Ergebnis zuzugreifen, für den Entwickler nichts anderes als warten.
Dass hier der Compiler seinen Magic Stick auspackt und daraus eine Callback-Methode macht ist (für die meisten leider) nicht ersichtlich.
Trotzdem ist es asynchron.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo ihr beiden,

vermutlich werde ich es nicht schaffen, euch ganz zusammen zu bringen, aber mir scheint, dass ihr anderseits auch nicht soweit auseinander seid. Zum einen ist malignate nicht prinzipiell gegen Wrapper, sondern hat seine ursprünglichen Aussagen schon deutlich relativiert. Anderseits finde ich seinen Hinweis, dass man sich als Autor und als Benutzer von asynchronen Bibliotheksmethoden darüber Gedanken machen sollte, ob in bestimmten Szenarien möglicherweise unnötig viele Threads belegt/blockiert werden, durchaus angebracht, selbst wenn man asynchrone Wrapper grundsätzlich für legitim hält. So absolut und unvereinbar stehen sich die Meinungen m.E. gar nicht mehr gegenüber.

Auch bei der Sortierung liegt die Wahrheit wohl in der Mitte. Richtig ist, dass sich Sortierung durch Parallelität nicht (weiter) Beschleunigen lässt, wenn die Speicherbandbreite für den Zugriff auf die zu sortierenden Daten der limitierende Faktor ist. Bei den meisten Sortierverfahren sind viele Zugriffe auf die Daten und gar keine oder nur wenige aufwändige Prozessoroperationen erforderlich, so dass eher die Speicherbandbreite als die Rechenleistung der limitierende Faktor ist. Solange die Speicherbandbreite durch einen Core noch nicht ausgenutzt ist oder diese durch den Einsatz von lokalen Caches weiterer Cores ausreichend erhöht wird, kann und wird Parallelität durchaus zu einer Beschleunigung führen. Es hängt also von den genauen Umständen ab, welcher Fall zutrifft.

herbivore
private Nachricht | Beiträge des Benutzers
malignate
myCSharp.de - Member

Avatar #avatar-3206.png


Dabei seit:
Beiträge: 751

beantworten | zitieren | melden

Danke, perfekt Schlussatz :)

Edit: Ich muss doch noch kurz erwähnen, dass ich seit November fast wöchentlich darauf hoffe, dass MongoDB endlich Asynchronität unterstützt ;)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von malignate am .
private Nachricht | Beiträge des Benutzers