Десериализация и асинхронность / ожидание - PullRequest
3 голосов
/ 19 декабря 2011

В моем приложении (Windows 8 Metro) я храню некоторые объекты в локальной папке в сериализованном формате.Вот метод для чтения, затем обратно (см. Ниже).

Если я вызываю этот метод с помощью Task.Run, я могу получить объект:

var entity= Task.Run<Entity>(() => GetASync<Entity>(file)).Result;

, но если я использую ключевое слово await, это не работает - в строке A (ReadObject) в методе поток останавливается и завершается без ошибок или исключений:

var entity= await GetASync<Entity>(file);

Может быть, я не использую await / async, как рекомендуется?

Метод

private async Task<T> GetASync<T>(IStorageFile file) where T : class
{
    try
    {    
        if (file != null)
        {
            IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
            IInputStream inputStream = readStream.GetInputStreamAt(0);                   
            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(inputStream.AsStream(), XmlDictionaryReaderQuotas.Max))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                var entity = serializer.ReadObject(reader); //line A - here the problem 
                return entity as T;
            }                    
        }
        else
        {
            return null;
        }

    }
    catch (FileNotFoundException)
    {
        return null;
    }
    catch (Exception)
    {
        throw;
    }
}

Ответы [ 2 ]

3 голосов
/ 19 декабря 2011

Ну, я понятия не имею, почему ваш код не работает. Я подозреваю, что тупик, но не должно быть . :)

Однако у меня есть пара рекомендаций по производительности, которые, вероятно, позволят избежать этой проблемы в качестве побочного эффекта. Во-первых, использовать ConfigureAwait(false):

IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read)
                                           .StartAsTask()
                                           .ConfigureAwait(false);

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

1 голос
/ 21 декабря 2011

Ping-back от http://social.msdn.microsoft.com/Forums/en-US/async/thread/3f192a81-073a-47ea-92e2-5ce02bf5ad33:

Вы столкнулись с известной проблемой в предварительной версии разработчика .NET, которую Microsoft распространила на конференции BUILD. Проблема вызвана некоторыми тонкими особенностями потока пользовательского интерфейса WinRT. В результате любая блокировка WinRT stream-IO из управляемого кода приведет к взаимоблокировке, если она выполняется из потока пользовательского интерфейса. Асинхронный ввод-вывод (например, ReadAsync) будет работать нормально. Команда разработчиков знает об этой проблеме и работает над ее устранением.

Обратите внимание, однако, что даже если и когда проблема устранена, выполнение блокировки ввода-вывода в потоке пользовательского интерфейса не является хорошей идеей. Ваша заявка будет заблокирована и не будет отвечать на все действия. Некоторые API-интерфейсы .NET не имеют асинхронных эквивалентов (пока), и даже после их преобразования преобразование кода может потребовать работы. Если вам нужно выполнить блокирующую операцию ввода-вывода, обязательно выгрузите ее в пул потоков:

DoUIStuff();
Int32 x = await Task.Run(() => {
    OpenStream();
    PerformBlockingIO();
    ProcessResults();
    return ComputeIOResults();
});
UseIOResults(x);

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

...