12

msdn ドキュメント内で XmlWriter を使用した非同期の例を見つけましたhttp://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspx

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 倍、10 MB 未満のファイルでは 8 ~ 10 倍以上、同期コードが高速であることがわかりました。

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

4

3 に答える 3

11

まず、ベンチマークに疑問を持たなければなりません。100MB のファイルで 3 ~ 4 倍遅くなることは、非常に重要です。

しかし、とにかく、async物事をより速く行うことではありません。その手術が行われているに何か他のことをすることです。クライアント側では、応答性の利点が得られます。サーバー側では、スケーラビリティの利点が得られます。

トレードオフは、操作自体が実際には遅くなることです (ただし、3 ~ 4 倍遅くなるのではなく、少しだけ遅くなるはずです)。書き込みに真の非同期ストリームを使用していない可能性があります (非同期ストリームを取得するには、ファイル ストリームを非同期で開く必要があります)。

于 2013-05-20T01:47:26.137 に答える
5

を実装する際にいくつかの判断を下す必要がありますasync/await。つまり、待っている操作には、の小さなオーバーヘッドasync/awaitが価値があるほどの十分な遅延が含まれている可能性があります。Stephen が指摘しているように、Microsoftは経験則として50 ミリ秒を推奨しています。

サンプル コードでは、操作に 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は、Stephen がコメントで指摘したように、フラグを使用してファイルを開くなどの微妙なポイントも含まれます。

于 2016-05-23T12:39:29.707 に答える
2

Stephen Cleary の答えは正しく、答えとして受け入れられるべきだと思います。ただし、コメントするには大きすぎる可能性があるため、ここに私の視点を入れたいと思います。

私の意見では、async/await キーワードには、他の何よりも 2 つの重要な利点があります。

1) await はノンブロッキングの待機です - 従来、非同期タスクを開始し (別のスレッドなど)、その結果/完了が必要な場合は、Wait()、WaitAll()、Thread.Join() などを使用していました ( APM と EAP も使用しました - ポイント 2 で言及します)。これらはすべてブロッキング呼び出しです。つまり、スレッドをブロックします (Thread.Sleep など)。そのため、UI スレッドがブロックされると、UI がフリーズします。ブロックされる ThreadPool スレッドが多すぎると、ThreadPool は新しいスレッドを作成するオーバーヘッドを負担する必要があります。async/await を使用することで、ノンブロッキングの待機を実行できます。高レベルの async/await キーワードは、メソッドをステート マシン (たとえば、await の前後のデリゲートのセット) に分割し、非同期タスクが終了したときに (TPL タスク スケジューラを使用して) デリゲートをスケジュールします。このようにして、UI をフリーズさせたり、ThreadPool スレッドをブロックしたりすることなく待機できます。そう、

2) async/await は、コードの可読性を何億倍も向上させます。EAP または APM を使用したことがある場合 (これらはある意味でノンブロッキングです)、コードをひっくり返す必要があります。誰が誰を呼び出しているか、どこで例外を処理するかを把握するのが難しい。開発者にとっては悪夢。async/await を使用すると、同期のように見える非同期コードを記述できます。

async/await には、非同期コードについて考える独自の方法があり、独自の落とし穴があります。そのため、慎重に使用する必要があります。

MSDN の例は、API のデモンストレーションのみを目的としていると思います。

于 2013-05-24T23:11:42.683 に答える