我在尋找一個解釋,而不僅僅是一個解決方案。我已經知道了解決方案。盡管花了幾天時間研究有關基于任務的異步模式(TAP),異步和等待的MSDN文章,但我對某些更詳細的信息仍然感到困惑。我正在為Windows Store Apps編寫記錄器,并且希望同時支持異步和同步記錄。異步方法遵循TAP,同步方法應該隱藏所有這些內容,并且外觀和工作方式與普通方法類似。這是異步日志記錄的核心方法:private async Task WriteToLogAsync(string text){ StorageFolder folder = ApplicationData.Current.LocalFolder; StorageFile file = await folder.CreateFileAsync("log.log", CreationCollisionOption.OpenIfExists); await FileIO.AppendTextAsync(file, text, Windows.Storage.Streams.UnicodeEncoding.Utf8);}現在對應的同步方法...版本1:private void WriteToLog(string text){ Task task = WriteToLogAsync(text); task.Wait();}看起來正確,但是不起作用。整個程序永久凍結。版本2:嗯..也許任務沒有開始?private void WriteToLog(string text){ Task task = WriteToLogAsync(text); task.Start(); task.Wait();}這拋出 InvalidOperationException: Start may not be called on a promise-style task.版本3:嗯.. Task.RunSynchronously聽起來很有希望。private void WriteToLog(string text){ Task task = WriteToLogAsync(text); task.RunSynchronously();}這拋出 InvalidOperationException: RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method.版本4(解決方案):private void WriteToLog(string text){ var task = Task.Run(async () => { await WriteToLogAsync(text); }); task.Wait();}這可行。因此,2和3是錯誤的工具。但是1?1有什么問題,與4有什么區別?是什么導致1凍結?任務對象有問題嗎?有沒有明顯的僵局?
3 回答

鳳凰求蠱
TA貢獻1825條經驗 獲得超4個贊
async從同步代碼中調用代碼可能非常棘手。
我在博客上解釋了造成這種僵局的全部原因。簡而言之,每個上下文的開頭都有一個默認保存的“上下文”,await用于恢復該方法。
因此,如果在UI上下文中調用await此async方法,則在完成時,該方法將嘗試重新輸入該上下文以繼續執行。不幸的是,使用Wait(或Result)的代碼將在該上下文中阻塞線程,因此該async方法無法完成。
避免這種情況的準則是:
使用ConfigureAwait(continueOnCapturedContext: false)盡可能多地。這使您的async方法可以繼續執行而不必重新輸入上下文。
一直使用async。使用await代替Result或Wait。
如果您的方法自然是異步的,那么(可能)您不應該公開同步包裝器。
- 3 回答
- 0 關注
- 887 瀏覽
添加回答
舉報
0/150
提交
取消