c# - 创建 ActionBlock<T> 列表,该列表将在任何失败时完成

标签 c# async-await tpl-dataflow

在可能对“空”任务列表调用await 的情况下。

我如何等待 Task<T> 的列表,然后将新任务添加到等待列表中,直到任务失败或完成。

我确信一定有一个 Awaiter CancellationTokenSource 此问题的解决方案。

public class LinkerThingBob
{
    private List<Task> ofmyactions = new List<Task>();

    public void LinkTo<T>(BufferBlock<T> messages) where T : class
    {
        var action = new ActionBlock<IMsg>(_ => this.Tx(messages, _));

        // this would not actually work, because the WhenAny 
        // will not include subsequent actions.
        ofmyactions.Add(action.Completion);

        // link the new action block.
        this._inboundMessageBuffer.LinkTo(block);
    }

    // used to catch exceptions since these blocks typically don't end.
    public async Task CompletionAsync()
    {
        // how do i make the awaiting thread add a new action
        // to the list of waiting tasks without interrupting it
        // or graciously interrupting it to let it know there's one more

        // more importantly, this CompletionAsync might actually be called
        // before the first action is added to the list, so I actually need
        // WhenAny(INFINITE + ofmyactions)
        await Task.WhenAny(ofmyactions);
    }
}

我的问题是我需要一种机制,可以添加每个 action上面创建的实例为Task<T>当出现异常时将会完成。

我不知道如何最好地解释这一点,但是:

  • 必须至少调用一次 LinkTo<T> 才能完成任务已经完成了,所以我需要从一个无限的任务开始

  • 每次LinkTo<T>被调用时,必须将新操作添加到任务列表中,该任务可能已在另一个线程中等待。

最佳答案

没有任何内置的东西,但使用 TaskCompletionSource<T> 构建一个并不太难。 。 TCS 是当您想要等待某些内容并且尚未为其构造时使用的类型。 (自定义等待者适用于更高级的场景)。

在这种情况下,类似这样的内容就足够了:

public class LinkerThingBob
{
  private readonly TaskCompletionSource<object> _tcs = new TaskCompletionSource<object>();

  private async Task ObserveAsync(Task task)
  {
    try
    {
      await task;
      _tcs.TrySetResult(null);
    }
    catch (Exception ex)
    {
      _tcs.TrySetException(ex);
    }
  }

  public void LinkTo<T>(BufferBlock<T> messages) where T : class
  {
    var action = new ActionBlock<IMsg>(_ => this.Tx(messages, _));

    var _ = ObserveAsync(action.Completion);

    this._inboundMessageBuffer.LinkTo(block);
  }

  public Task Completion { get { return _tcs.Task; } }
}

Completion以未完成状态开始。可以使用ObserveAsync将任意数量的 block 链接到它。 。一旦其中一个 block 完成,Completion也完成。我写了ObserveAsync这里的方式是,如果第一个完成的 block 没有错误地完成,那么 Completion 也会如此。 ;如果第一个完成的 block 完成时出现异常,则 Completion将完成相同的异常。请随意调整以满足您的特定需求。 :)

关于c# - 创建 ActionBlock<T> 列表,该列表将在任何失败时完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34397095/

相关文章:

C# 大型 JSON 转字符串导致内存不足异常

c# - 将类型 Task<IEnumerable> 转换为类型 IEnumerable

c# - 在多个任务中(一次?)编辑哈希集是线程安全的吗?

c# - 为什么 block 按此顺序运行?

c# - 如何跨多个请求重用 HTTP 连接?

c# - Google directions api 网络服务 - 在 map 上显示响应。是否可以?

javascript - React 事件处理程序中的异步/等待

c# - 将动态创建的 ActionBlock 链接到 BufferBlock

c# - ActionBlock<T> 与 Task.WhenAll

c# - 通过扩展属性查询 Google API 联系人