传统观点认为async void
is ok in event handlers在GUI驱动的应用程序(例如WPF)中运行良好。
然而,在使用不同类型的事件处理程序时,我最近被这个假设所困扰。考虑一个应用程序,其中由于外部事件(例如RabbitMQ消息或某些第三方集成库)而调用事件处理程序。据推测,事件处理程序会被某种调度程序循环调用。
如果事件处理程序中的代码是同步的,那么一切都很好 - 它需要在事件处理程序再次触发之前完成执行。但是如果事件处理程序是async void
,则对事件处理程序的每次调用都是一次性的,并且许多将并行执行。
通常情况下,您不希望出现此行为。例如,如果我正在处理来自RabbitMQ队列的消息,我想按顺序处理消息。但是,我希望能够await
异步调用。
我如何拥有异步事件处理程序,但仍然按顺序执行它们?
更新:我遇到了blog post by Stephen Cleary,它描述了我遇到的完全相同的问题。但是,如果我理解正确,他建议使用延期假定您可以控制事件args(在我的情况下,我不会)。
答案 0 :(得分:0)
我认为事件调用者不应该关心这些事情。给定事件可能有多个订阅者,并且所有这些订阅者可能在事件处理程序中执行异步操作。您不希望在发布下一个事件之前等待所有完成,因为假设订户A在100毫秒内处理您的消息而订户B在10秒内处理它 - 那么您将浪费订阅者的时间什么都没有。
相反,在用户端解决这个问题。在事件处理程序中将传入消息放入某个队列并返回。同时处理与背景中的另一个线程一个一个地排队。
答案 1 :(得分:0)
创建一个计数为1的SemaphoreSlim
,然后在事件处理程序中调用WaitAsync
,然后再执行任何工作(确保完成后Release
) 。这将确保不超过1个处理程序同时工作。
如果您可以控制触发事件的对象,则可以使用更好的选项,但是由于您没有,所以您只能手动将所有处理程序彼此同步。