首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步加载XDocument

异步加载XDocument
EN

Stack Overflow用户
提问于 2017-04-24 14:08:32
回答 2查看 10.2K关注 0票数 12

我希望将大型XML文档加载到XDocument对象中。使用XDocument.Load(path, loadOptions)的简单同步方法效果很好,但在加载大型文件(特别是从网络存储中)时,会在GUI上下文中阻塞很长时间。

我编写这个异步版本的目的是提高文档加载的响应能力,特别是在通过网络加载文件时。

代码语言:javascript
复制
    public static async Task<XDocument> LoadAsync(String path, LoadOptions loadOptions = LoadOptions.PreserveWhitespace)
    {
        String xml;

        using (var stream = File.OpenText(path))
        {
            xml = await stream.ReadToEndAsync();
        }

        return XDocument.Parse(xml, loadOptions);
    }

但是,在从本地磁盘加载的200 MB XML原始文件上,同步版本在几秒钟内完成。异步版本(在32位上下文中运行)将抛出一个OutOfMemoryException

代码语言:javascript
复制
   at System.Text.StringBuilder.ToString()
   at System.IO.StreamReader.<ReadToEndAsyncInternal>d__62.MoveNext()

我认为这是因为临时字符串变量用于将原始XML保存在内存中,以便由XDocument进行解析。据推测,在同步场景中,XDocument.Load()能够在源文件中进行流处理,并且永远不需要创建一个巨大的字符串来保存整个文件。

有什么办法让这两个世界都占优势吗?用完全异步I/O加载XDocument,而不需要创建大的临时字符串?

EN

回答 2

Stack Overflow用户

发布于 2021-01-21 12:36:58

延迟回答,但我也需要在“遗留”.NET框架版本上读取异步,所以我想出了一种方法,可以以异步的方式真正读取内容,而不需要恢复到内存中缓冲XML数据。

由于XDocument.CreateWriter()提供的写入器不支持异步写入,因此XmlWriter.WriteNodeAsync()失败,所以代码执行异步读取并将其转换为同步写入XDocument-writer。然而,代码的灵感来自于XmlWriter.WriteNodeAsync()的工作方式。由于作者构建了内存中的DOM,这实际上比实际执行异步写入更好。

代码语言:javascript
复制
public static async Task<XDocument> LoadAsync(Stream stream, LoadOptions loadOptions) {
    using (var reader = XmlReader.Create(stream, new XmlReaderSettings() {
            DtdProcessing = DtdProcessing.Ignore,
            IgnoreWhitespace = (loadOptions&LoadOptions.PreserveWhitespace) == LoadOptions.None,
            XmlResolver = null,
            CloseInput = false,
            Async = true
    })) {
        var result = new XDocument();
        using (var writer = result.CreateWriter()) {
            do {
                switch (reader.NodeType) {
                case XmlNodeType.Element:
                    writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                    writer.WriteAttributes(reader, true);
                    if (reader.IsEmptyElement) {
                        writer.WriteEndElement();
                    }
                    break;
                case XmlNodeType.Text:
                    writer.WriteString(await reader.GetValueAsync().ConfigureAwait(false));
                    break;
                case XmlNodeType.CDATA:
                    writer.WriteCData(reader.Value);
                    break;
                case XmlNodeType.EntityReference:
                    writer.WriteEntityRef(reader.Name);
                    break;
                case XmlNodeType.ProcessingInstruction:
                case XmlNodeType.XmlDeclaration:
                    writer.WriteProcessingInstruction(reader.Name, reader.Value);
                    break;
                case XmlNodeType.Comment:
                    writer.WriteComment(reader.Value);
                    break;
                case XmlNodeType.DocumentType:
                    writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
                    break;
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace:
                    writer.WriteWhitespace(await reader.GetValueAsync().ConfigureAwait(false));
                    break;
                case XmlNodeType.EndElement:
                    writer.WriteFullEndElement();
                    break;
                }
            } while (await reader.ReadAsync().ConfigureAwait(false));
        }
        return result;
    }
}
票数 2
EN

Stack Overflow用户

发布于 2017-04-25 07:35:26

首先,任务不是异步运行的。您需要使用内置的异步IO命令,或者自己在线程池上拆分一个任务。例如

代码语言:javascript
复制
public static Task<XDocument> LoadAsync
 ( String path
 , LoadOptions loadOptions = LoadOptions.PreserveWhitespace
 )
{
    return Task.Run(()=>{
     using (var stream = File.OpenText(path))
        {
            return XDocument.Load(stream, loadOptions);
        }
    });
}

如果使用Parse的流版本,则不会得到临时字符串。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43590338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档