反序列化和异步/等待

时间:2011-12-18 21:32:57

标签: c# windows-8 async-ctp async-await

在我的应用程序(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 个答案:

答案 0 :(得分:3)

好吧,我不知道为什么你的代码不起作用。我怀疑是一个死锁,但不应该是一个。 :)

但是,我确实有一些性能建议可能会避免这个副作用。第一种是使用ConfigureAwait(false)

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

另一种是将文件读入内存(异步),然后解析它。 (我假设您的代码中每个文件存储一个对象)。

答案 1 :(得分:1)

http://social.msdn.microsoft.com/Forums/en-US/async/thread/3f192a81-073a-47ea-92e2-5ce02bf5ad33进行反击:

您遇到了Microsoft在BUILD会议上分发的.NET开发人员预览版中的已知问题。 问题是由WinRT UI线程的一些细微特性引起的。因此,如果从UI线程执行,任何阻止来自托管代码的WinRT流-IO都将导致死锁。异步IO(例如ReadAsync)可以正常工作。开发团队意识到了这个问题,并正在努力解决它。

但请注意,即使问题得到解决,在UI线程上执行阻止IO也不是一个好主意。您的应用程序将在操作期间阻止并无响应。有些.NET API没有异步等效(甚至),甚至一旦他们这样做,转换代码可能需要工作。如果必须执行阻塞IO操作,请确保将其卸载到线程池:

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

这样可以始终保持应用程序的响应速度。作为副作用,您还将解决上述错误并避免死锁。