【问题标题】:Avoiding use of ActionBlock<TInput>.Post when PostDataflowBlockOptions.BoundedCapacity is not the default value?当 PostDataflowBlockOptions.BoundedCapacity 不是默认值时避免使用 ActionBlock<TInput>.Post?
【发布时间】:2020-05-26 07:35:10
【问题描述】:

我听说,当您决定使用 BoundedCapacity 属性时,如果使用 Post 方法而不是 SendAsync 对象的 SendAsync 方法,可能会丢失信息。

有人能解释一下为什么会这样吗?

【问题讨论】:

    标签: c# asynchronous .net-core async-await dataflow


    【解决方案1】:

    Post 方法尝试同步发布项目并返回 truefalse,具体取决于块是否接受该项目。不接受商品的原因:

    1. 块被标记为已完成(通过调用其Complete 方法)。
    2. 块已完成,无论成功或失败(其Completion.IsCompleted 属性返回true)。
    3. 该块的容量有限(选项BoundedCapacity != -1),其缓冲区当前已满。

    SendAsync 方法尝试异步发布项目并返回Task&lt;bool&gt;。此任务将始终完成,除非块具有有限容量,其缓冲区当前已满,并且当前未完成或未标记为已完成。这是SendAsync 将异步运行的唯一情况。等待任务后,任务的bool结果表明该块是否接受了该项目。不接受商品的原因:

    1. 在调用SendAsync 之前或在等待期间将该块标记为已完成。
    2. 该块在调用SendAsync 之前完成,或者由于异常而在等待期间完成,或者因为调用了它的Fault 方法。

    所以PostSendAsync 之间的区别是第 (3) 点。在具有完整缓冲区的有限容量块的情况下,它们的行为不同。在这种情况下,Post 会立即拒绝该项目,而SendAsync 将在缓冲区再次有可用空间时异步接受它。

    在大多数情况下,SendAsync 的行为是理想的行为。使用Post 而不是SendAsync 可以看作是一个等待发生的错误,当一段时间后块被重新配置为有界时,以解决新发现的与内存使用过多相关的问题。

    最好不要忽略这两种方法的返回值,因为返回值false 在大多数情况下表示存在错误。很少期待并准备好处理false 结果。一些想法:

    if (!block.Post(item)) throw new InvalidOperationException();
    
    if (!await block.SendAsync(item)) throw new InvalidOperationException();
    
    var accepted = block.Post(item); Debug.Assert(accepted);
    
    var accepted = await block.SendAsync(item); Debug.Assert(accepted);
    

    【讨论】:

    • 如果您完全控制并且 100% 确定数据块尚未完成,那么忽略 SendAsync 方法的实际返回值不是完全安全吗?对于Post,这很重要,因为如果您确实有一个有限容量集,那么您的数据元素就不会排队等待工作(如果它正在处理BoundedCapacity 属性中指定的最大元素数量)
    • @SpiritBob 是的,如果您正在编写一个您不希望再次接触的一次性程序,那么您可以不用考虑这些方法的返回值。但是,如果您正在编写一个预计会发展的程序,那么今天为自己节省几秒钟(通过省略Debug.Assert)可能会让您在未来失去几个小时的挫败感。或者更糟糕的是,这可能不仅会让你感到沮丧,还会让你感到尴尬。没有人会欣赏产生错误结果的程序,而且很难评估失去客户信任的成本。
    • @SpiritBob 抱歉,如果我之前的评论有点苛刻。它揭示了我对可能发生的错误有多么害怕。它是不可预测的、无声的,并且可能对数据造成永久性损坏。所要做的就是在项目的后期添加一个看起来不错的配置。
    • 我具体情况的问题是,我不能让等待SendAsync完成的奢侈。我能做的最好的事情是在触发该方法后立即检查任务的IsFaulted 属性是否为真?
    • @SpiritBob SendAsync 返回的任务永远不会失败。所以它的IsFaulted 属性永远不会变成true。如果您不能异步等待Task 完成,那么Post 方法可能更适合您的情况。只要确保检查它的返回值,如果它返回false,就采取相应的行动。如果这仍然不是一个选项,那么最后一个选择是不使用BoundedCapacity 设置。
    【解决方案2】:

    是的,您可能会丢失信息,Post 更有可能这样做,但 SendAsync 也可能会丢失信息。假设您有一个 ActionBlock 需要 1000 毫秒才能完成,在此期间发布了 10 条消息。对于ActionBlockBoundedCapacity 设置为 5。结果,最后5条消息没有被处理,信息丢失。

    这里有一些关于它的细节: TPL Dataflow, whats the functional difference between Post() and SendAsync()?

    查看第二个答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-03
      • 1970-01-01
      相关资源
      最近更新 更多