2014-12-10 25 views
2

下面的列表中無效項的奇裝異服是所涉及的代碼:在任務

private static async Task DoRunInOrderAsync<TTaskSeed>(SemaphoreSlim sem, IObservable<TTaskSeed> taskSeedSource, CreateTaskDelegate<TTaskSeed> createTask, OnTaskErrorDelegate<TTaskSeed> onFailed, OnTaskSuccessDelegate<TTaskSeed> onSuccess) where TTaskSeed : class 
{ 
    var tasks = await taskSeedSource 
     .Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem)) 
     .ToList() 
     .ToTask(); 

    await Task.WhenAll(tasks); 
} 
private static async Task GetPendingOrRunningTask<T>(T taskSeed, CreateTaskDelegate<T> createTask, OnTaskErrorDelegate<T> onFailed, OnTaskSuccessDelegate<T> onSuccess, 
    SemaphoreSlim sem) where T : class 
{ 
    Exception exc = null; 
    await sem.WaitAsync(); 
    try 
    { 
     var task = createTask(taskSeed); 
     if (task != null) 
     { 
      await task; 
     } 
     onSuccess(task, taskSeed); 
    } 
    catch (Exception e) 
    { 
     exc = e; 
    } 

    sem.Release(); 

    if (exc != null) 
    { 
     onFailed(exc, taskSeed); 
    } 
} 

其中:

  • SelectIObservable<TResult> Select<TSource, TResult>(this IObservable<TSource> source, Func<TSource, TResult> selector)System.Reactive.Linq.Observable
  • ToListSystem.Reactive.Linq.Observable
  • IObservable<IList<TSource>> ToList<TSource>(this IObservable<TSource> source)
  • ToTaskTask<TResult> ToTask<TResult>(this IObservable<TResult> observable)System.Reactive.Threading.Tasks.TaskObservableExtensions
  • System.Reactive.Linq版本是2.2.5.0

enter image description here

據我所看到的,一切都建,周圍沒有過時的二進制文件。錯誤經常發生,但並非總是如此。

對於我的生活,我不明白是怎麼tasks列表可以包含null如果GetPendingOrRunningTask方法是async Task

編輯

enter image description here

所以ToList注入null。怎麼樣?爲什麼?我做錯了什麼(除了編程爲生)?

+0

你知道Rx的序列化合約嗎?請參閱[Rx設計指南]中的第4.2節(http://go.microsoft.com/fwlink/?LinkID=205219)。信號量不應該是必需的,因爲你的'taskSeedSource'不能推送重疊的通知。如果是這樣,那麼它違反了一個重要的Rx合約,這可能會引起運營商內部的競爭狀況。 – 2014-12-11 01:49:46

+0

請注意,如果要按順序而不是併發地運行任務,則使用'FromAsync'將它們投影到observables中,並調用'Concat'而不是'ToList'。 – 2014-12-11 01:54:20

+0

只有當信號量計數初始值爲1時,它纔會按順序排列。但它可能是N,在這種情況下,我想同時處理至多N個種子,直到處理完所有種子。名字中的「InOrder」有點令人困惑,並且出於歷史原因。 – mark 2014-12-11 01:58:55

回答

2

您可能有競爭條件。

.ToList()調用List<T>構造函數。代碼是here

如果taskSeedSource中元素的數量在構造函數啓動和完成之間發生變化,則可能最終導致列表不一致。特別看看94行。

ICollection<T> c = collection as ICollection<T>; 
if(c != null) { 
    int count = c.Count; 
    if (count == 0) 
    { 
     _items = _emptyArray; 
    } 
    else { 
     _items = new T[count]; 
     c.CopyTo(_items, 0); /* it's possible there are now fewer elements in c */ 
     _size = count; 
    } 
}