2

我尝试使用异步/等待功能从 XElement 对象写入 xml 文件。但我意识到 XElement.Save() 不适用于异步/等待。

也许解决方案可以将 XElement.Save(Stream) 与 FileStream 对象一起使用...

所以,我写了一些代码如下,但很难用文件流来处理。

public async Task SaveAsync(XElement xml, string filename)
{
    using (var fs = new FileStream(filename, FileMode.Create))
    {
        xml.Save(fs);
        await fs.WriteAsync(**please_help_me**);
    }
}

如何使用这种方法或有其他解决方案吗?

4

3 回答 3

6

如果您真的不想阻塞 IO(并挂起 ThreadPool 线程/您的线程),您可能需要使用临时 MemoryStream:

using(var ms = new MemoryStream())
using(var fs = new FileStream("myFile", FileMode.Create))
{
    xml.Save(ms);
    ms.Position = 0;
    await ms.CopyToAsync(fs)
}
于 2012-09-18T17:20:29.507 回答
2

XElement没有任何方法可以异步编写自己,因此您使用它进行的任何调用都将是同步的。如果您需要使此方法异步(例如,这发生在 UI 线程中,并且您希望在后台线程中执行此操作,以便在保存 XML 时应用程序不会出现“冻结”),您可能想开始一个新任务,并将其保存在后台。

public async Task SaveAsync(XElement xml, string filename)
{
    await Task.Factory.StartNew(delegate
    {
        using (var fs = new FileStream("myFile", FileMode.Create))
        {
            xml.Save(fs);
        }
    });
}
于 2012-09-18T16:50:05.040 回答
2

.NET Core 2.0.NET Standard 2.1开始,XElement两者XDocument都有SaveAsync()方法。因此,您现在可以执行以下操作:

public static async Task SaveAsync(this XElement xml, string filename, SaveOptions options = default, CancellationToken cancellationToken = default)
{
    // "await using" introduced in c# 8 / .NET Core 3.0+
    await using var stream =
        new FileStream(
        filename, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, 
        useAsync: true);

    await xml.SaveAsync(stream, options, cancellationToken);
}

笔记:

  • 在 .NET Core 3 中,XDocument.SaveAsync()(也可能XElement.SaveAsync())仍然包含至少一个阻塞调用。请参阅XDocument.SaveAsync 有一个阻塞调用 #29464。该问题应在.NET 5中修复。

  • 根据文档,构造函数的useAsync参数FileStream

    指定是使用异步 I/O 还是使用同步 I/O。但是请注意,底层操作系统可能不支持异步 I/O,因此当指定 true 时,句柄可能会根据平台同步打开。当异步打开时,BeginRead(Byte[], Int32, Int32, AsyncCallback, Object)BeginWrite(Byte[], Int32, Int32, AsyncCallback, Object)方法在大读取或写入时性能更好,但对于小读取或写入它们可能要慢得多。如果应用程序旨在利用异步 I/O,请将 useAsync 参数设置为 true。正确使用异步 I/O 可以将应用程序加速多达 10 倍,但使用它而不为异步 I/O 重新设计应用程序可以将性能降低多达 10 倍。

    既然你知道你想写你的XElement异步,大概你已经为异步 I/O 设计了你的应用程序。但是,您可能希望在使用和不使用异步 IO 的情况下进行基准测试,以确认您没有损害性能。

演示小提琴在这里

于 2020-12-14T21:35:25.157 回答