下面是我最近用來說明使用異步解決方案的差異和各種問題的代碼片段序列。
假設您在基於GUI的應用程序中有一些事件處理程序花費了大量時間,因此您希望使其處於異步。這裏是你開始的同步邏輯:
while (true) {
string result = LoadNextItem().Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
break;
}
}
LoadNextItem返回一個Task,它最終會產生一些你想檢查的結果。如果當前結果是您正在查找的結果,則更新UI上某個計數器的值,然後從該方法返回。否則,您將繼續處理來自LoadNextItem的更多項目。
異步版本的第一個想法:只使用continuations!讓我們暫時忽略循環部分。我的意思是,什麼可能會出錯?
return LoadNextItem().ContinueWith(t => {
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
});
太棒了,現在我們有一種方法不會阻塞!它崩潰了。 UI控件的任何更新都應該在UI線程上發生,因此您需要對此進行說明。值得慶幸的是,有指定的延續應該如何安排的選項,並有一個默認的只是這一點:
return LoadNextItem().ContinueWith(t => {
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
},
TaskScheduler.FromCurrentSynchronizationContext());
太好了,現在我們有一個不死機的方法!它反而失敗了。繼續是他們自己的獨立任務,他們的地位與先前的任務沒有關係。因此,即使LoadNextItem發生故障,調用者也只會看到已成功完成的任務。好吧,那只是傳遞異常時,如果有一個:
return LoadNextItem().ContinueWith(t => {
if (t.Exception != null) {
throw t.Exception.InnerException;
}
string result = t.Result;
if (result.Contains("target")) {
Counter.Value = result.Length;
}
},
TaskScheduler.FromCurrentSynchronizationContext());
太好了,現在該實際工作。對於單個項目。現在,那個循環如何?事實證明,解決方案相當於原來的同步版本的邏輯將是這個樣子:
Task AsyncLoop() {
return AsyncLoopTask().ContinueWith(t =>
Counter.Value = t.Result,
TaskScheduler.FromCurrentSynchronizationContext());
}
Task<int> AsyncLoopTask() {
var tcs = new TaskCompletionSource<int>();
DoIteration(tcs);
return tcs.Task;
}
void DoIteration(TaskCompletionSource<int> tcs) {
LoadNextItem().ContinueWith(t => {
if (t.Exception != null) {
tcs.TrySetException(t.Exception.InnerException);
} else if (t.Result.Contains("target")) {
tcs.TrySetResult(t.Result.Length);
} else {
DoIteration(tcs);
}});
}
或者,而不是所有上述情況,你可以使用異步做同樣的事情:
async Task AsyncLoop() {
while (true) {
string result = await LoadNextItem();
if (result.Contains("target")) {
Counter.Value = result.Length;
break;
}
}
}
現在好多了,不是嗎?
來源
2013-09-24 13:10:16
pkt
如果您刪除在第二個例子中'Wait'通話*然後*這兩個片段會(大部分)等同。的 – Servy
可能重複的[是異步等待關鍵字相當於ContinueWith拉姆達?](http://stackoverflow.com/questions/8767218/is-async-await-keyword-equivalent-to-a-continuewith-lambda) –
供參考:您的'getWebPage'方法不能在兩個代碼中使用。在第一個代碼中它有一個'Task'返回類型,而在第二個代碼中它有'string'返回類型。所以基本上你的代碼不能編譯。 - 如果要精確。 –