Нагрузка XDocument используется асинхронно

Я хочу загрузить большие XML-документы в объекты XDocument. Простой синхронный подход с использованием XDocument.Load(path, loadOptions) отлично работает, но блокирует в течение неудобно долгого времени в контексте GUI при загрузке больших файлов (особенно из сетевого хранилища).

Я написал эту асинхронную версию с целью улучшения отзывчивости при загрузке документов, особенно при загрузке файлов по сети.

    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 МБ XML raw-файл, загруженный с локального диска, синхронная версия завершается через несколько секунд. Асинхронная версия (работает в 32-разрядном контексте), а не выдает OutOfMemoryException:

   at System.Text.StringBuilder.ToString()
   at System.IO.StreamReader.<ReadToEndAsyncInternal>d__62.MoveNext()

Я предполагаю, что это из-за временной строковой переменной, используемой для хранения необработанного XML в памяти для синтаксического анализа XDocument. Предположительно, в синхронном случае XDocument.Load() способен передавать через исходный файл и никогда не нужно создавать одну огромную строку для хранения всего файла.

есть ли способ получить лучшее обоих миров? Загрузите XDocument С полностью асинхронным вводом-выводом и без необходимости создания большой временной строки?

2 ответов


прежде всего задача не выполняется асинхронно. Вам нужно будет использовать встроенную команду async IO или самостоятельно выполнить задачу в пуле потоков. Например

public static async Task<XDocument> LoadAsync
 ( String path
 , LoadOptions loadOptions = LoadOptions.PreserveWhitespace
 )
{
    return Task.Run(()=>{
     using (var stream = File.OpenText(path))
        {
            return XDocument.Load(stream, loadOptions);
        }
    });
}

Если вы используете потоковую версию разбора, то вы не получите временную строку.