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