我在msdn文档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倍,在我的环境中,小于10mb的文件,我的同步代码快了8-10倍。
那么我的问题是,有没有这样的代码是可用的,并提供合理的性能收益的场景?
发布于 2013-05-20 09:47:26
首先,我必须对基准测试提出质疑。对于100MB的文件来说,速度慢3-4倍是非常重要的。
但不管怎样,async并不是为了让事情做得更快。它是关于在操作进行的同时做一些其他的事情。在客户端,您可以获得响应能力的好处;在服务器端,您可以获得可伸缩性的好处。
折衷是操作本身实际上更慢(但它应该稍微慢一点,而不是慢3-4倍)。很可能您并没有使用真正的异步流进行写入(您必须专门异步打开一个文件流才能获得一个异步流)。
发布于 2016-05-23 20:39:30
在实现async/await时,有一些判断要求:即,您正在等待的操作是否可能包含足够的延迟,以至于async/await的小开销是值得的。作为Stephen points out,微软的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标志打开文件这样的微妙之处。
发布于 2013-05-25 07:11:43
我认为Stephen Cleary的答案是正确的,应该被接受为答案。然而,我只想把我的观点放在这里,因为它可能太大了,无法评论。
在我看来,async/await关键字有两个显著的优势:
1) await是一个非阻塞等待-传统上,当我们启动一个异步任务(比如在另一个线程上)并想要它的结果/完成时,我们使用了Wait(),WaitAll(),Thread.Join()等(我们也使用了APM和EAP -我会在第二点提到它)。这些都是阻塞调用-意味着它们阻塞线程(如Thread.Sleep)。因此,如果UI线程阻塞,UI将冻结--如果太多的ThreadPool线程阻塞,那么ThreadPool不得不承受创建新线程的开销。通过使用async/await -我们能够执行非阻塞等待。在高层,async/await关键字将把方法分解成一个状态机(例如,等待之前和之后的一组委托),并在异步任务结束时调度委托(使用TPL任务调度程序)。这样我们就可以在不冻结UI或阻塞ThreadPool线程的情况下等待。因此,总结async/await将节省资源(线程),并且不会加快速度-它将有自己的状态机和调度开销。
2) async/await将代码的可读性提高了无数倍-如果你使用过EAP或APM (它们在某种程度上是非阻塞的)-那么你必须颠倒你的代码。很难弄清楚谁在调用谁-在哪里处理异常。开发人员的噩梦。使用async/await,我们可以编写看起来像同步的异步代码。
async/await有它自己的方式来思考异步代码,并且有它自己的一组陷阱-所以,你必须小心地使用它。
我认为MSDN上的示例只是为了演示API。
https://stackoverflow.com/questions/16641074
复制相似问题