2013-05-20 22 views
7

I Beispiel Dokumentation Asynchron mit den XmlWriter innerhalb Msdn gefunden haben http://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspxXmlWriter asynchrone Methoden

async Task TestWriter(Stream stream) 
{ 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.Async = true; 
    using (XmlWriter writer = XmlWriter.Create(stream, settings)) { 
     await writer.WriteStartElementAsync("pf", "root", "http://ns"); 
     await writer.WriteStartElementAsync(null, "sub", null); 
     await writer.WriteAttributeStringAsync(null, "att", null, "val"); 
     await writer.WriteStringAsync("text"); 
     await writer.WriteEndElementAsync(); 
     await writer.WriteProcessingInstructionAsync("pName", "pValue"); 
     await writer.WriteCommentAsync("cValue"); 
     await writer.WriteCDataAsync("cdata value"); 
     await writer.WriteEndElementAsync(); 
     await writer.FlushAsync(); 
    } 
} 

Alles, was ich über Themen und asynchrone Programmierung kennen, sagte mir, dass dies zu langsam Code ist und synchrone Write-Methoden verwenden, wird sein viel schneller. Ich habe diesen Code geändert und getestet. Ich habe festgestellt, dass ich richtig bin und synchronen Code schneller in 3-4 mal auf Dateien mehr als 100 MB und mehr als 8-10 mal schneller auf Dateien weniger als 10 MB auf meinem env.

Also meine Frage gibt es irgendein Szenario, wo solcher Code verwendbar ist und angemessene Leistungssteigerungen bietet?

Antwort

9

Zunächst muss ich das Benchmarking in Frage stellen. 3-4 mal langsamer auf 100MB Dateien ist wirklich signifikant.

Aber egal, async geht es nicht darum, Dinge schneller zu machen. Es geht darum, etwas anderes zu tun während dieser Vorgang läuft. Auf der Clientseite erhalten Sie den Vorteil der Reaktionsfähigkeit; Auf der Serverseite profitieren Sie von der Skalierbarkeit.

Der Nachteil ist, dass die Operation selbst ist eigentlich langsamer (aber es sollte nur ein wenig langsamer, nicht 3-4 mal langsamer). Wahrscheinlich verwenden Sie keinen wirklich asynchronen Stream zum Schreiben (Sie müssen einen Dateistream speziell asynchron öffnen, um einen asynchronen Stream zu erhalten).

+0

Hier ist mein Testcode auf Pastebin http://pastebin.com/67EfUbPN –

+1

Wie ich vermutete, öffnen Sie den Dateistream nicht asynchron. Weitere Informationen finden Sie in der [MSDN-Dokumentation (erste paar Absätze unter Bemerkungen)] (http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx). –

+0

Auch wenn ich FileOptions.Asynchron wie dieser Stream str = File.Create (FILE_NAME_A, 6140, FileOptions.Asynchronous); es wird nur um 5-10% langsamer –

2

Ich denke, Stephen Cleary Antwort ist richtig und sollte als Antwort akzeptiert werden. Ich möchte hier jedoch nur meinen Standpunkt darlegen, da er für einen Kommentar zu groß sein könnte.

Meiner Meinung nach async/erwarten Keywords, aus alles andere, hat zwei wesentliche Vorteile:

1) warten auf eine nicht-blockierende Wartezeit ist - Traditionell, wenn wir eine asynchrone Aufgabe (sagen über einen anderen Thread starten) und wollen sein Ergebnis/Abschluss, wir haben Wait(), WaitAll(), Thread.Join() usw. verwendet (wir haben auch APM und EAP verwendet - ich werde es in Punkt 2 erwähnen). Dies sind alles blockierende Aufrufe - was bedeutet, dass sie den Thread blockieren (wie Thread.Sleep). Wenn UI-Threadblöcke blockiert werden, friert die Benutzeroberfläche ein - wenn zu viele ThreadPool-Threads blockieren, muss ThreadPool den Overhead des Erstellens neuer Threads freisetzen. Durch die Verwendung von async/await können wir nicht blockierende Wartezeiten durchführen. Bei async/await-Schlüsselworten auf hoher Ebene wird die Methode in eine Zustandsmaschine zerlegt (z. B. eine Gruppe von Delegaten vor und nach dem Warten) und den Delegaten planen (mithilfe des TPL-Task-Schedulers), wenn die asynchrone Task beendet ist. Auf diese Weise können wir warten, ohne die Benutzeroberfläche einzufrieren oder ThreadPool-Threads zu blockieren. So summiert Async/erwarten Sie Ressourcen (Threads) und wird nicht beschleunigen Zeug - es wird seinen eigenen Overhead der Zustandsmaschine und Zeitplanung haben.

2) async/await erhöht die Lesbarkeit von Code um ein Vielfaches - wenn Sie EAP oder APM verwendet haben (sie sind nicht blockierend) - dann müssen Sie Ihren Code auf den Kopf stellen. Schwierig herauszufinden, wer wen anruft - wo man mit der Ausnahme umgehen kann. Alptraum für Entwickler. Mit async/await können wir asynchronen Code schreiben, der wie synchron aussieht.

async/await hat seine eigene Art, wie man über asynchronen Code denkt und hat seine eigenen Fehler - also muss man es vorsichtig benutzen.

Ich denke, das Beispiel in MSDN ist nur für API-Demonstrationszwecke.

1

Es gibt einige Beurteilung Anrufe bei der Umsetzung async/await: nämlich, ist die Operation erwarten Sie wahrscheinlich genug Verzögerung, dass der kleine Aufwand von async/await lohnt sich.Als Stephen points out, Microsoft recommends 50 milliseconds als Daumenregel Schwelle.

In Ihrem Beispielcode ist es ziemlich unwahrscheinlich, dass Ihre Operationen mehr als 50 Millisekunden dauern.

Ihre real-world CDATA Abschnitte könnten ein lohnender Kandidat für async/erwarten sein. In der realen Welt schreiben wir häufig base64-kodierte PDFs in XML-Streams. In einem solchen Beispiel können Sie feststellen, dass das Warten auf den Teil Ihres Codes lohnt.

async Task TestWriter(Stream stream, Stream sourceDocument) 
{ 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.Async = true; 
    using (XmlWriter writer = XmlWriter.Create(stream, settings)) 
    { 
     writer.WriteStartElement("pf", "root", "http://ns"); 
     writer.WriteStartElement(null, "sub", null); 
     writer.WriteAttributeString(null, "att", null, "val"); 
     writer.WriteString("text"); 
     writer.WriteEndElement(); 


     // Write the source document 
     writer.WriteStartElement(null, "SourceDocument", null); 
     Byte[] buffer = new Byte[4096]; 
     int bytesRead = await sourceDocument.ReadAsync(buffer, 0, 4096); 
     while (bytesRead > 0) 
     { 
      await writer.WriteBase64Async(buffer, 0, bytesRead); 
      bytesRead = await sourceDocument.ReadAsync(buffer, 0, 4096); 
     } 
     writer.WriteEndElement(); // SourceDocument 

     writer.WriteEndElement(); // pf 
     await writer.FlushAsync(); 
    } 
} 

Natürlich, wenn Sie async/await in einem beliebigen Teil des Codes abbeißen, können Sie es in Ihrem gesamten Call-Stack implementiert werden muss, um es lohnt sich, auch subtile Punkte wie Dateien mit der async Flagge Öffnen als Stephen bemerkt in seine Kommentare.

Verwandte Themen