2013-05-20 18 views
7

私はスレッドと非同期プログラミングについて知っていることすべてが、これは遅すぎるコードで、同期書き込み方法を使用することが可能になることを私に言ったMSDNドキュメント内のXmlWriterのhttp://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspxのXmlWriter非同期メソッド

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(); 
    } 
} 

を使用して非同期の例を発見しましたはるかに高速。私はこのコードを修正し、それをテストしました。私は、私が正しいと同期コードは、より速く100Mb以上のファイルで3-4回、ファイル上で8~10回以上速く、私のenvで10mb未満であることがわかった。

私の質問は、このようなコードが使用可能で、妥当なパフォーマンス向上をもたらすシナリオはありますか?

答えて

9

最初に、私はベンチマークに疑問を呈しています。 100MBのファイルでは3〜4倍遅くなっています。

ただし、asyncに関係なく、高速化は行われません。それは何か他のことをすることです。、そして、操作が行われているのはです。クライアント側では、応答性の利点が得られます。サーバー側ではスケーラビリティの利点があります。

実際には、操作自体は実際には遅いですが(遅くても3〜4倍遅くする必要はありません)本当に非同期のストリームを書くのではなく、ファイルストリームを非同期的に開いて非同期のストリームを取得する必要があります。

+0

ここに私のテストコードがありますpastebin http://pastebin.com/67EfUbPN –

+1

私は疑うが、ファイルストリームを非同期に開くことはありません。詳細については、[MSDNドキュメント(備考の最初の数段落)](http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx)を参照してください。 –

+0

このストリームのようにFileOptions.Asynchronousを使用しても、str = File.Create(FILE_NAME_A、6140、FileOptions.Asynchronous);それは5-10%だけ遅くなります –

2

私はスティーブン・クレアリーの答えが正しいと答えて答えるべきだと思います。しかし、私はちょうどコメントのために大きすぎるかもしれないので、ここに私の視点を入れたいです。私の意見非同期/で

キーワードを待つには、他のすべての外に、二つの重要な利点があります。)

1を待つ非ブロック待ちである - 伝統的に、我々は非同期タスクを起動したときに(別のスレッド上で言います) Wait()、WaitAll()、Thread.Join()などを使用しています(APMとEAPも使用しました - ポイント2で言及します)。これらはすべて呼び出しをブロックします。つまり、Thread.Sleepのようにスレッドをブロックします。したがって、UIスレッドがブロックすると、UIがフリーズします.TopPoolスレッドが多すぎるとブロックされた場合、ThreadPoolは新しいスレッドを作成するためのオーバーヘッドをかけなければなりません。 async/awaitを使用することで、非ブロック待機を実行できます。高レベルのasync/awaitキーワードでは、非同期タスクが終了したときに、メソッドを状態マシン(たとえば、待っている前後のデリゲートのセット)に分割し、デリゲートをスケジュールします(TPLタスクスケジューラを使用します)。このように、我々は、UIを凍結またはThreadPoolのスレッドをブロックせずに待つことができます。 async/awaitを集計すると、リソース(スレッド)が節約され、処理速度が向上しません。ステートマシンとスケジューリングのオーバーヘッドが発生します。

2)async/awaitはコード可読性を桁外れに増加させます.EAPまたはAPMを使用した場合(非ブロッキングの場合)、コードを逆さまにする必要があります。誰が誰を呼んでいるのか把握するのが難しい - 例外を処理する場所。開発者のための悪夢。 async/awaitを使用すると、同期のように見える非同期コードを書くことができます。非同期/を待つ

を使用すると、非同期コードについてどのように考えるかの独自の方法を持っており、落とし穴の独自のセットを持っている - そう、人は慎重に使用する必要があります。

私は、MSDN上の例は単なるAPIのデモンストレーションの目的のためだと思います。

1

async/awaitを実装するときに判断する必要があります。すなわち、async/awaitの小さなオーバーヘッドが価値がある十分な遅延を含む可能性が高い操作です。Stephen points outとして、Microsoft recommends 50 millisecondsを親指の基準として適用します。

サンプルコードでは、操作に50ミリ秒以上かかることはほとんどありません。

あなたの実際のCDATAセクションは、async/awaitにとって価値のある候補かもしれません。現実世界では、base64でエンコードされたPDFをXMLストリームに書き出すことがよくあります。このような例では、のコード部分がの価値があると待っていることがあります。もちろん

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(); 
    } 
} 

、あなたのコードのいずれかの部分でasync/awaitをかみ切る場合、あなたはスティーブンに述べたようにasyncフラグを使用してファイルを開くような微妙な点を含めて、それは価値がある作るためにあなたのコールスタック全体でそれを実装する必要があります彼のコメント

関連する問題