2013-05-20 3 views
7

Я нашел пример асинхронного использования XmlWriter в MSDN документации http://msdn.microsoft.com/en-us/library/system.xml.xmlwriter.aspxXmlWriter метода асинхронной

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

Все, что я знаю о потоках и асинхронном программировании сказал мне, что это слишком медленный код и использовать синхронные методы Write будет намного быстрее. Я изменил этот код и протестировал его. Я обнаружил, что я прав и синхронный код быстрее в 3-4 раза на файлы более 100 МБ и более чем в 8-10 раз быстрее на файлы размером менее 10 МБ на моем env.

Итак, мой вопрос в том, есть ли какой-либо сценарий, когда такой код можно использовать и обеспечивает разумную прибыль от производительности?

ответ

9

Прежде всего, мне нужно подвергнуть сомнению бенчмаркинг. В 3-4 раза медленнее на 100 МБ файлы действительно значительны.

Но независимо от того, 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, как этот Stream str = File.Create (FILE_NAME_A, 6140, FileOptions.Asynchronous); он становится только медленнее на 5-10% –

2

Я думаю, что ответ Стивена Клири правильный и должен быть принят как ответ. Тем не менее, я просто хочу поставить свою точку зрения здесь, поскольку она может быть слишком большой для комментариев.

На мой взгляд асинхронном/ждут ключевых слов, из всего остального, имеет два существенных преимущества:

1) ждать не является блокировании ожидание - Традиционно, когда мы начинаем асинхронную задачу (скажем, над другим потоком) и хотим его результат/завершение, мы использовали Wait(), WaitAll(), Thread.Join() и т. д. (мы также использовали APM и EAP - я упомянул об этом в пункте 2). Это все блокирующие вызовы - это значит, что они блокируют поток (например, Thread.Sleep). Таким образом, если блоки потоков пользовательского интерфейса, пользовательский интерфейс замерзнет - если слишком много потоков ThreadPool блокируется, тогда ThreadPool должен обнажить накладные расходы на создание новых потоков. С помощью async/wait - мы можем выполнить неблокирующее ожидание. На высоких уровнях async/await ключевые слова будут разбивать метод на конечный автомат (например, набор делегатов до и после ожидания) и планировать делегат (используя планировщик задач TPL), когда задача async завершена. Таким образом, мы можем ждать, не замораживая пользовательский интерфейс или блокируя потоки ThreadPool. Итак, суммирование async/await будет экономить ресурсы (потоки) и не ускорит работу - у него будут свои собственные накладные расходы на конечный автомат и планирование.

2) async/await увеличивает читаемость кода на gazillion раз - если вы использовали EAP или APM (они не блокируются в некотором смысле) - тогда вам нужно перевернуть свой код вверх ногами. Трудно понять, кто звонит, кто - где обрабатывать исключение. Кошмар для разработчика. Используя async/await, мы можем написать асинхронный код, который выглядит синхронно.

async/await имеет свой собственный способ, как вы думаете об асинхронном коде и имеет свой собственный набор gotchas - так что нужно использовать его осторожно.

Я думаю, что пример на MSDN предназначен только для демонстрации API.

1

При реализации async/await необходимо принять во внимание суждения: именно операция, которую вы ожидаете, включает достаточную задержку, что стоит небольшая накладная плата async/await.Как Stephen points out, Microsoft recommends 50 milliseconds как правило большой порог.

В вашем примере кода маловероятно, что любая из ваших операций займет более 50 миллисекунд.

Ваши разделы CDATA реального мира могут быть достойным кандидатом для async/wait. В реальном мире мы часто выписываем PDF-файлы с кодировкой base64 в 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 флагом, как Стивен отметил в его комментарии.

Смежные вопросы