【问题标题】:Guaranteed order of processing in EventHandler subscriberEventHandler 订阅者中的保证处理顺序
【发布时间】:2019-06-06 09:03:22
【问题描述】:

我有一个异步调用的 EventHandler(使用 BeginInvoke/EndInvoke)。

提供的 EventArgs 包含一个递增值。

事件正在快速连续地多次引发;引发事件的顺序是,它们的 EventArgs 值在每次后续调用时递增。

在订阅者中,我试图按照它们被引发的顺序处理这些事件,并且我在订阅者中有一个锁定,以确保我只能同时处理一个事件,但是,我有一个问题是锁定并不总是按照请求的顺序进行处理,导致事件被无序处理。

我在这里看到:Does lock() guarantee acquired in order requested? 这在某种程度上是意料之中的;即我不能依赖按请求顺序获取锁。

该问题的一个答案将我引导到此处的排队锁实现:Is there a synchronization class that guarantee FIFO order in C#?

在我走这条路之前,我有三个问题:-

  1. 如果(快速)引发多个事件,是否总是按照引发事件的顺序调用订阅者的处理程序?
  2. 如果我像上面提到的那样实现一个排队锁,我可以依靠Enter() 方法以正确的顺序调用吗? (即,即使在“事件 1”之后触发了“事件 2”,“事件 2”仍会在“事件 1”之前到达我的订阅者中的queuedLock.Enter() 的风险);和
  3. 鉴于 EventHandler 需要是异步的(以防止订阅者阻塞线程),这对 EventHandler 来说是不可能/合理的吗?我是否需要实现某种单独的异步事件队列?

【问题讨论】:

    标签: c# multithreading event-handling synchronization locking


    【解决方案1】:

    如果(快速)引发多个事件,是否总是按照引发事件的顺序调用订阅者的处理程序?

    没有。首先,对 BeginInvoke 的每次调用都会将一个工作项排队到线程池中;每个工作项在不同的线程上执行,并且这些线程处于竞争中。其次,即使您的订阅者以正确的顺序被调用,这些调用仍然在竞争;如果您在订阅者中获取锁,则未定义授予锁的顺序。

    如果我像上面提到的那样实现一个排队锁,我可以依靠 Enter() 方法以正确的顺序调用吗? (即,即使在“事件 1”之后触发了“事件 2”,“事件 2”仍会在“事件 1”之前到达我的订阅者中的 queuedLock.Enter() 的风险);

    不,原因与上述相同。

    鉴于 EventHandler 需要异步(以防止订阅者阻塞线程),这对 EventHandler 来说是不可能/合理的吗?我是否需要实现某种单独的异步事件队列?

    是的。由于您必须按顺序处理事件,因此使用队列优于多线程。生成多个线程只是为了让它们都等待获取单个锁是没有意义的。

    使用队列

    当使用队列时,生产者只会将事件排入队列而不会阻塞。在消费者方面,有一个线程逐个出列和处理事件。这是每个事件调用订阅者的线程。请注意,当队列为空时,消费者线程将被阻塞。

    您仍然可以并行处理

    例如,如果一个事件属于(假设)一个客户,来自同一个客户的事件必须按顺序处理,而来自两个不同客户的两个事件可以独立处理。

    在这种情况下,您可以将属于不同客户的事件分离到多个队列中,并且每个队列有一个单独的消费者线程。为此,您必须确保来自同一客户的事件映射到同一队列。

    例如,如果你有 N 个队列,你可以通过计算 hash(Customer) 模 N 来将一个事件映射到一个队列。

    现有的生产者-消费者队列

    .NET 提供了几个专门的队列,开箱即用:

    你也可以看看:

    【讨论】:

    • 感谢您提供高质量的答案和线程建议。我猜这个前提在一开始就存在根本性的缺陷,一旦你将异步带入等式,你就放弃了保证顺序的能力。我正在寻找一种方法来使用现有事件来表示我在队列中有项目,但意识到我刚刚将同样的问题移到了不同​​的位置。现在,我正在轮询 ConcurrentQueue,同时重新考虑如何解决问题。
    猜你喜欢
    • 1970-01-01
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多