【问题标题】:Strange appearance of a null entry in the list of tasks任务列表中出现奇怪的空条目
【发布时间】:2014-12-10 23:10:22
【问题描述】:

这里是涉及的代码:

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&lt;TResult&gt; Select&lt;TSource, TResult&gt;(this IObservable&lt;TSource&gt; source, Func&lt;TSource, TResult&gt; selector) 来自 System.Reactive.Linq.Observable
  • ToListIObservable&lt;IList&lt;TSource&gt;&gt; ToList&lt;TSource&gt;(this IObservable&lt;TSource&gt; source) 来自 System.Reactive.Linq.Observable
  • ToTaskTask&lt;TResult&gt; ToTask&lt;TResult&gt;(this IObservable&lt;TResult&gt; observable) 来自 System.Reactive.Threading.Tasks.TaskObservableExtensions
  • System.Reactive.Linq 版本为 2.2.5.0

据我所知,一切都已构建,周围没有陈旧的二进制文件。该错误经常发生,但并非总是如此。

对于我的生活,如果GetPendingOrRunningTask 方法是async Task,我无法理解tasks 列表如何包含null

编辑

所以ToList 注入null。如何?为什么?我做错了什么(除了以编程为生)?

【问题讨论】:

  • 你知道 Rx 的序列化合约吗?请参阅Rx Design Guidelines 中的第 4.2 节。信号量不是必需的,因为您的 taskSeedSource 不得推送重叠通知。如果是,那么它违反了重要的 Rx 合同,这可能会导致运营商内部出现竞争条件。
  • 请注意,如果您想按顺序而不是同时运行任务,请使用FromAsync 将它们投影到可观察对象中并调用Concat 而不是ToList
  • 仅当信号量计数最初为 1 时它是顺序的。但它可能是 N,在这种情况下,我想同时处理最多 N 个种子,直到处理完所有种子。名称中的 InOrder 有点令人困惑,并且出于历史原因。
  • 刚刚阅读了 Rx 的序列化合约。所以,看来我需要使用 Serialize 运算符,对吧?
  • @DaveSexton - 请安排您的评论作为答案,我想感谢您。

标签: c# linq asynchronous async-await system.reactive


【解决方案1】:

你可能有竞争条件。

.ToList() 调用 List&lt;T&gt; 构造函数。代码是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;
    }
} 

【讨论】:

    猜你喜欢
    • 2023-04-11
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多