2014-09-22 11 views
7

In .NET 4.5 gibt es viele Methoden, die jetzt in asynchronen und nicht asynchronen Paaren wie Flush() und FlushAsync() kommen. Im Idealfall sind I/O-Interaktionen immer asynchron (Sie können immer mit .Wait() blocken, wenn Sie das wirklich wollen), aber die nicht-asynchronen (blockierenden) Versionen müssen natürlich aufgrund der Abwärtskompatibilität bestehen bleiben.asynchrone vs nicht asynchrone Methoden in einer neuen Bibliothek

Beim Ausrollen einer vollständig neuen Bibliothek, die keine Einschränkungen der Rückwärtskompatibilität aufweist, gibt es einen Grund, warum man die nicht-asynchronen Methoden einbeziehen würde?

+1

Ich würde sagen, das ist ein bisschen eigensinnig (weil, wenn Sie sie nur überladen mit Warte in Ihrer Implementierung als nichts gewonnen werden kann), aber ich würde diese enthalten - keine Notwendigkeit, Ihren Benutzer zu async zwingen, wenn er nicht will (egal ob seine Gründe gut oder schlecht sind) - aber das ist nur meine * Meinung * (node.js Leute werden eine ganz andere haben) - deshalb könnte deine Frage bald geschlossen sein - es kann keine gute Antwort geben – Carsten

+0

I glaube nicht, dass es nur eine Frage der Meinung ist ... Ich bin mir ziemlich sicher, dass es irgendwo eine Art Richtlinie oder Best Practice gibt. Andererseits ist eine Best Practice eine Meinung, also sollten wir vielleicht nicht nach Best Practices zu Stack Overflow fragen? – Gigi

+0

@Gigi vielleicht solltest du * this * auf Meta fragen;) - ich wollte dir nur einen Hinweis geben, wieso du jetzt 2 nahe Flaggen hast - nicht zu streiten – Carsten

Antwort

0

Der einzige Grund ist, wenn Sie Support-Anwendungen, die ein .NET Framework vor 4.5 zielt. Wenn Sie über solche Anwendungen verfügen und Ihre neue Bibliothek verwenden möchten, müssen Sie die nicht asynchrone Methode verwenden.

Sie können Ihre neue Assembly auch mit .NET 4.0 kompilieren, indem Sie Async Targeting Package. verwenden. Ich schlage vor, dass Sie zwei Projekte erstellen: eins mit 4.5 und eins mit 4.0.

+0

Eigentlich 4,0 ist auch gut ohne ATP, Sie können einfach nicht 'erwarten' verwenden. Was natürlich bedeutet, dass es sehr schwierig ist, die Dinge in Ordnung zu bringen, aber ich bin schon so oft gezwungen worden, und es funktioniert. Und natürlich, wenn Sie in Ihrer Bibliothek "erwarten", müssen Ihre Kunden auch 4/4.5 sein, so dass die nicht asynchronen Versionen sowieso nicht helfen werden. – Luaan

6

Async-Methoden sind normalerweise mit Kosten verbunden, da es eine vom Compiler generierte Zustandsmaschine gibt, die ziemlich viel zusätzlichen Code ergibt. Wenn Sie nicht die async Methoden verwenden, werden sie nicht aktiviert, so dass Sie diese Kosten vermeiden.

Wenn Sie die async Version verwenden und rufen Sie einfach Wait() Sie riskieren eine deadlock und auch würden Sie einen zusätzlichen Kontextwechsel entstehen, sobald der async Vorgang abgeschlossen ist. Insgesamt würde das Ergebnis also etwas schlechter ausfallen.

Auch alle Ausnahmen, die Sie erhalten, werden nun in eine AggregatedException verpackt, so dass es zusätzliche Arbeit in der Ausnahmeverarbeitung gibt. Werfen Sie einen Blick auf Async Performance: Understanding the Costs of Async and Await

+2

Dies ist ein guter Punkt, Sie sollten jedoch bedenken, dass all diese Kosten im Vergleich zur zugrundeliegenden E/A-Anforderung fast immer trivial sind. Die Verwendung von asynchronem I/O ist praktisch immer gut (schließlich macht man dasselbe, wenn man zB File.ReadAllBytes macht - es passiert nur in einer unteren Ebene). Die Verwendung für die CPU-Arbeit usw. ist teurer, aber es gibt * eine Richtlinie, die verhindert, dass 'XXXAsync'-Methoden einfach einen synchronen Code in' Task.Run' einbinden. Wenn Sie also richtiges asynchrones Arbeiten machen, sind die Kosten nicht ' t so schlecht. – Luaan

+0

Das ist eigentlich sehr interessant. Aber wenn die asynchrone Methode die asynchrone Methode nicht einfach umbrechen kann, wie gehen Sie dann vor, sie beide zu implementieren, ohne Code zu duplizieren? – Gigi

+0

@Gigi Nun, es ist nicht unbedingt Code-Duplizierung, aber ja, Sie werden den Code nicht "wiederverwenden". Wenn Sie einfach ein 'Wait' auf die Async-Methode (oder' Task.Run' auf der Sync-Methode, Gott bewahre: D) gemacht haben, hat es keinen Sinn, die Methode dort zu haben. Sieh dir die. An.NET Referenz Quellcode, können Sie sehen, wie es mit z. 'FileStream' (mit einigen komplizierten Async/Sync-Methoden) oder' Socket' (was ziemlich einfach ist). – Luaan

4

Neds Antwort ist ziemlich gut, also werde ich nicht wiederholen, was er sagte (obwohl beachten Sie, dass der Overhead nicht unbedingt groß im Vergleich zu den Kosten der E/A-Operation selbst ist).

Ein weiterer wichtiger Grund, die synchronen Methoden zur Verfügung zu stellen, ist eigentlich im Nachhinein offensichtlich - Leute haben ernsthafte Schwierigkeiten, asynchrone Operationen zu verstehen. Sie sind es gewohnt, "Lesen, dann schreiben, dann wieder lesen ..." Fehlerbehandlung, Fehlerlokalität, Synchronisation ... alle können sehr schwierig werden, besonders wenn Sie await nicht verwenden können.

Die Wahrheit ist, während es sehr schön wäre, wenn alles im Laufe der Zeit asynchron wird, ist es viel schwieriger, über asynchrone Anwendungen zu begründen. Es ist immer noch besser als Multi-Threading, aber nicht viel.

Auf diese Weise kann die Verwendung von asynchronen Methoden als eine Optimierung angesehen werden - und Sie tun keine Optimierungen, wenn Sie wissen sie werden erheblich helfen. Für eine Bibliothek ist dies schwer zu entscheiden - also bieten beide Möglichkeiten. Jemand, der einen Server mit hohem Durchsatz schreibt, wird die Sorgfalt auf sich nehmen, die benötigt wird, um eine performante und zuverlässige asynchrone Anwendung zu schreiben. Jemand, der gerade ein einfaches CMS schreibt, möchte es vielleicht komplett vermeiden.

Dies gilt insbesondere für C#/NET unter 4,5 -. Versuchen, Fehler zu tun Umgang auf asynchrone Fortsetzungen ohne await, und Sie werden sehen, was ich rede

:)

Keeping Code einfach ist sehr wichtig. Es senkt die Entwicklungs- und Wartungskosten erheblich und erleichtert Neueinsteigern das Verständnis.

4

Es gibt kleine Unterschiede (meistens vernachlässigbar) zwischen async und synchronen Versionen, aber ich würde sagen, dass gibt es keinen Grund mehr beide Versionen der gleichen Operation zu haben. Sie sollten bei der Implementierung Ihrer Bibliothek entscheiden, welche Version am besten passt. Eine natürlich asynchrone Operation (z. B. das Herunterladen einer Datei) sollte async sein und CPU-gebundene Operationen sollten synchron sein.

Sie können das Paradigma sehen im Rahmen WinRT verwendet:

diese Ziele zu erreichen, haben wir viele potenziell I/O-bound APIs asynchron in der Windows-Runtime. Dies sind die wahrscheinlichsten Kandidaten, um die Leistung sichtbar zu verschlechtern, wenn sie synchron geschrieben werden (z. B. könnte die Ausführung länger als 50 Millisekunden dauern). Dieser asynchrone Ansatz für APIs ermöglicht es Ihnen, Code zu schreiben, der standardmäßig schnell und flüssig ist, und fördert die Bedeutung der App-Reaktionsfähigkeit bei der App-Entwicklung im Metro-Stil.

Von Keeping apps fast and fluid with asynchrony in the Windows Runtime

Früher ist es der Fall sein, dass die asynchronen Überlastungen mit war immens schwieriger und komplizierter als die synchron diejenigen so beid Versionen mit einer guten Idee war. Mit async-await ist das nicht mehr der Fall.