如何使用异步倒计时事件而不是收集任务并等待它们?

时间:2014-12-09 18:48:16

标签: c# asynchronous system.reactive

我有以下代码:

var tasks = await taskSeedSource
    .Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
    .ToList()
    .ToTask();

if (tasks.Count == 0)
{
    return;
}

if (tasks.Contains(null))
{
    tasks = tasks.Where(t => t != null).ToArray();
    if (tasks.Count == 0)
    {
        return;
    }
}

await Task.WhenAll(tasks);

taskSeedSource是反应性观察者。可能是这段代码有很多问题,但我看到至少有两个:

  1. 我正在收集任务,而我却没有它。
  2. 不知何故,返回的任务列表可能包含空值,即使GetPendingOrRunningTaskasync方法,因此永远不会返回null。我不明白为什么会这样,所以我不得不在不了解问题原因的情况下对其进行辩护。
  3. 我想使用AsyncEx框架中的AsyncCountdownEvent而不是收集任务然后等待它们。

    因此,我可以将倒计时事件传递给GetPendingOrRunningTask,它将立即递增它并在等待完成其内部逻辑后返回之前发出信号。但是,我不明白如何将倒计时事件整合到monad中(这是反应行话,不是吗?)。

    这样做的正确方法是什么?

    修改

    伙计们,让我们忘记返回列表中的神秘空值。假设一切都是绿色的,代码是

    var tasks = await taskSeedSource
        .Select(taskSeed => GetPendingOrRunningTask(taskSeed, ...))
        .ToList()
        .ToTask();
    
    await Task.WhenAll(tasks);
    

    现在的问题是我如何使用倒计时事件做到这一点?所以,假设我有:

    var c = new AsyncCountdownEvent(1);
    

    async Task GetPendingOrRunningTask<T>(AsyncCountdownEvent c, T taskSeed, ...)
    {
      c.AddCount();
      try
      {
        await ....
      }
      catch (Exception exc)
      {
        // The exception is handled
      }
      c.Signal();  
    }
    

    我的问题是我不再需要返回的任务。收集和等待这些任务以获取所有工作项目结束的时刻,但现在倒计时事件可用于指示工作何时结束。

    我的问题是我不确定如何将其整合到Reactive链中。基本上,GetPendingOrRunningTask可以是async void。在这里,我被困住了。

    编辑2

    Strange appearance of a null entry in the list of tasks

1 个答案:

答案 0 :(得分:1)

@Servy是正确的,你需要在源头解决null Task问题。没有人想回答有关如何解决违反您自己定义的方法的合同但尚未提供检查来源的问题的问题。

关于收集任务的问题,如果您的方法返回通用Merge,则很容易避免使用Task<T>

await taskSeedSource
  .Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
  .Where(task => task != null)  // According to you, this shouldn't be necessary.
  .Merge();

然而,遗憾的是,非通用Merge没有正式的Task重载,但这很容易定义:

public static IObservable<Unit> Merge(this IObservable<Task> sources)
{
  return sources.Select(async source =>
  {
    await source.ConfigureAwait(false);
    return Unit.Default;
  })
  .Merge();
}