2017-03-06 50 views
1

我已經讓自己陷入了與任務混亂的境地,我不確定擺脫它的好方法。如何避免「Unobserved Task」異常?

我有數據要從兩個不同的API異步獲取。這種聯繫是可疑的,我可以等待的時間有限。期望的行爲是「我想等待2秒鐘以獲得兩組數據,如果2秒過期,我會採取任何已完成的任務,即使這沒有任何結果。」 (它已經運行在一個工作線程,所以同步等待是沒有問題的。)

Task<IData> firstTask = _firstDataSource.GetDataAsync() 
Task<IData> secondTask = _secondDataSource.GetDataAsync() 

var whenBothTasksFinish = Task.WhenAll(firstTask, secondTask); 

var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2)); 

Task.WhenAny(whenBothTasksFinish, timeoutTask).Wait() 

bool timedOut = timeoutTask.IsCompleted 

if (timedOut) { 
    return newIData[0]; 
} 

var sources = new List<IData>(); 
if (firstTask.IsCompleted && !firstTask.IsFaulted) { 
    sources.Add(firstTask.Result); 
} else if (firstTask.IsFaulted) { 
    LogException(firstTask.Exception); 
} 

// Same block as above for secondTask 

它的混亂,但我是:

我懷着一種janky設置這樣的拉這一關當我寫這篇文章的時候,它變得狹窄。也許還有更好的辦法可以解決這個問題,今晚我會想到這一點。現在我很困惑如何解決這個問題。

問題發生在關閉網絡連接時,兩個IData任務均失敗。自從我記錄它們的異常以來,我滿足了會導致UnobservedTaskException的條件。但是它們的異常也會冒泡到Task.WhenAll()和Task.WhenAny()中。這最終得到最終確定,我的應用程序拋出UnobservedTaskException。奇怪的是,這似乎並不一致崩潰的應用程序,但它確實有時這就是爲什麼我關心。

我環顧四周,似乎像我可以處理,這是一個相當簡單的延續的一種方式:

whenBothTasksFinish.ContinueWith(t => LogException(t.Exception), TaskContinuationOptions.OnlyOnFaulted); 

我不只是這樣做的唯一原因是我喜歡如何在當前結構讓我提供更個性化的日誌消息:我關心哪個任務拋出異常。我不想記錄我得到的混亂的AggregateException,但是並沒有將它解開太多。

這很晚了,我沒有花很多時間重新思考這個算法。有沒有辦法確保我承認任務異常或重組此結構以獲得我想要的結果而不涉及太多移動部件?

回答

0

我嘗試了很多不同的東西,到達此解決方案:

whenBothTasksFinish.ContinueWith((parent) => { 
    var flattened = parent.Exception.Flatten(); 
    flattened.Handle((ex) => true); 
    }, TaskContinuationOptions.OnlyOnFaulted); 

在正常情況下,這將是一個壞主意。這相當於一個空的try/catch。但在我的情況下,我將在稍後分別處理每個例外情況。這使得框架退出抱怨,我沒有處理來自WhenAll(的異常)。

奇怪:當我在Xamarin Studio中調試時,保持斷點太長有時會導致WhenAll()任務在繼續運行之前收集。我可能可以通過GC.KeepAlive()來處理,但是meh。