C# 如何使用TPL数据流处理输入的完整列表?

C# 如何使用TPL数据流处理输入的完整列表?,c#,tpl-dataflow,C#,Tpl Dataflow,我是TPL数据流的新手,我让它工作,但我不确定我是否正确使用它。我有一个输入(字符串)列表,我想以最大程度的并行性处理它们(全部),并知道何时全部完成。现在我只是通过输入调用foreach,并在ActionBlock上调用Post,忽略返回值。这似乎不正确,因为它可能会丢失输入 我的问题是:如何避免丢失项目?是否有一个内置的块,我可以只给我的输入,它将确保他们都尝试?(无论每个输入是否成功。) 我看到的建议基本上包括: await block.Completion; 这是否说明输入失败(其中P

我是TPL数据流的新手,我让它工作,但我不确定我是否正确使用它。我有一个输入(字符串)列表,我想以最大程度的并行性处理它们(全部),并知道何时全部完成。现在我只是通过输入调用
foreach
,并在
ActionBlock
上调用
Post
,忽略返回值。这似乎不正确,因为它可能会丢失输入

我的问题是:如何避免丢失项目?是否有一个内置的块,我可以只给我的输入,它将确保他们都尝试?(无论每个输入是否成功。)

我看到的建议基本上包括:

await block.Completion;
这是否说明输入失败(其中
Post
sendsync
将返回false)?对我来说,奇怪的是,这个决定似乎是在我调用
Post
时做出的,而不是在之后,所以这个
Completion
甚至不包括这些项目

我觉得我基本上需要一个重试循环来处理前一次无法处理的输入,类似于:

while (items.Count > 0) {
  foreach (var item in items) {
    if (await block.SendAsync(item)) {
      items.Remove(item);
    }
  }

  await block.Completion;
}

block.Complete();
(除了更好的循环处理/错误检查。)

这个额外的级别是否不必要?还是我在某个地方在概念上错了

这似乎不正确,因为它可能会丢失输入

假设您使用的是默认值,这是正确的<如果块拒绝输入,则code>Post仅返回
false
。如果块已接收到
完成
信号,或者块的输入缓冲区已满,则可能发生这种情况。默认情况下,每个块的输入缓冲区可以无限增长,因此具有默认输入缓冲区大小的
ActionBlock
只有在调用
Complete
后才会从
Post
返回
false


ActionBlock
最常见的用例是使用and,其中代码仅在添加所有项后调用
Complete
。在这种情况下,
Post
将永远不会返回
false
,您可以安全地忽略返回值。

如果块已完成,或者如果块的输入缓冲区已满,则方法
Post
将返回false。由于该设置并不是什么异国情调,并且在项目的后期可能需要它来解决RAM使用率高的新问题,因此我认为使用
Post
方法而忽略结果是不安全的。为了防止出现涉及丢失消息(可能是订单或发票)的不有趣的错误,您可以执行以下操作:

foreach (var item in items)
{
    var accepted = block.Post(item);
    if (!accepted) throw new InvalidOperationException("Item was not accepted");
}
这样,您至少会被通知有东西坏了,并且不会让小车行为悄悄进入

另一方面,等待和忽视结果要安全得多。在发生异常或取消的情况下,
SendAsync
通常会返回
false
,在这种情况下,您将在
等待
块的
完成时收到通知。因此,在这种情况下不需要抛出异常

foreach (var item in items)
{
    await block.SendAsync(item).ConfigureAwait(false);
}
出于性能原因,您可以同时使用
Post
SendAsync
。只有当你有数以千万计的项目需要处理时,这才会产生影响

foreach (var item in items)
{
    if (!block.Post(item))
    {
        await block.SendAsync(item).ConfigureAwait(false);
    }
}
相关的: