2011-12-18 94 views
3

在我的應用程序(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; 
    } 
} 
+0

它是否適用於'file = null'的普通情況? – svick 2011-12-19 10:01:35

+0

svick,yes的確如此 – MatthieuGD 2011-12-19 11:50:52

+0

僅供參考,你的解決方法應該是'var entity = await Task.Run (()=> GetASync (file));' - 你不想在異步代碼中訪問Result,因爲它不同地處理錯誤。 – 2011-12-19 13:01:55

回答

3

好了,我不知道爲什麼你的代碼不能正常工作。我懷疑是一個僵局,但是不應該是。 :)

但是,我確實有一些性能建議,可能會避免作爲副作用的問題。第一是使用ConfigureAwait(false)

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

另一種是將文件讀入存儲器(異步地)和然後解析它。 (我從你的代碼中假設你正在爲每個文件存儲一個對象)。

+0

謝謝斯蒂芬,第一個建議就是這麼做的,但我不確定爲什麼......對於第二個建議,我不明白性能問題,你能解釋一下嗎? – MatthieuGD 2011-12-19 11:50:02

+0

'ReadObject'是同步的。因此,它會在讀取期間阻塞一個線程池線程(如果您取出'ConfigureAwait',那麼它會阻塞UI線程)。此外,'IInputStream'包裝器在異步讀取時實現同步讀取作爲阻塞 - 這意味着分配了更多的對象(例如'ManualResetEvent')。最好的解決方案是一個'ReadObjectAsync',但AFAIK不存在(但),所以一個可接受的解決方案是異步讀取文件到內存中,然後(同步)解析它。這樣你就沒有在I/O上阻塞線程池線程。 – 2011-12-19 12:58:24

+0

關於* why * it works:我懷疑'ReadObject'中的死鎖,它在讀取期間阻塞了UI線程。如果底層的異步讀取試圖在UI線程上完成(它不應該這樣做),就會發生死鎖。我查看了WinRT包裝器,但是看不到它會做什麼。 'ConfigureAwait'通過在讀取操作開始之前移除UI上下文來工作 - 所以底層異步讀取現在將在線程池線程上完成。但它確實會讓我感到不安,因爲它不應該是必需的。 – 2011-12-19 13:12:36

1

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

你擊中,微軟在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); 

這樣,你讓你的應用程序響應在任何時候。作爲一個副作用,您還將解決上述錯誤並避免死鎖。