在我的许多订阅者的情况下,异步事件的优点或替代方案

本文关键字:方案 事件 许多订 我的 情况下 异步 | 更新日期: 2023-09-27 18:26:00

让我们假设我有一个类Item。项的值取自外部源。要获得最新的值,必须在循环中尽可能快地请求该值。

当然,Item不仅有1个,还有数千个。就像:

while(active)
{
  foreach(Item item in items)
  {
    item.Value = RequestValue(item.Address);
  }
}

每个项目都可以使用多次。为了获得更改,Item有一个ValueChanged事件,您可以在其中订阅。

假设我有很多订阅者,大概有100或1000个。每次处理都会花费时间,并且可能会延迟变量后面的循环。其想法是:使事件异步。在这种情况下,处理程序需要多长时间并不重要。然而,在这个问题中:"异步引发所有事件是推荐的做法吗?"没有人建议异步事件(除非有良好的性能原因)。

我做了一个小的性能测试。我创建了一个SyncItemAsyncItemSubscriber。如果值已经改变,则SyncItem正在调用OnValueChanged并且AsyncItem正在调用new Thread(() => {OnValueChanged();}).Start();

我使用Timer来更改值(以引发事件)。我用了一个快速测试(每50毫秒)和一个慢速测试(3秒)。

我使用了很多Subscriber和以下处理程序:

处理器1

//Nothing
//Slow test: Sync is faster
//Fast test: Sync is faster, Async closing window does not exit application

处理器2

Thread.Sleep(...);
//Slow test: Sync gets slower the higher the time is, at ~ 10ms equal to async
//Fast test: Times varying, Async closing window does not exit application

处理器3

Dispatcher.BeginInvoke(new Action(() => { control.Text = value; } ));
//Slow test: Sync is faster (async needs longer than with Handler 1)
//Fast test: both UI does not react properly, Async UI also only rarely updated

处理器4

Dispatcher.Invoke(() => { control.Text = value; });
//Slow test: Async is faster, sync test: UI does not react properly
//Fast test: Sync UI does not react properly, Async OutOfMemoryException

我想在大多数情况下,会使用处理程序2(任何需要一些时间的复杂方法),有时也会使用UI处理程序3或4。主要是因为处理程序2,异步事件处理似乎更快。

但是,我觉得使用异步事件并不舒服。除了性能,还有其他好的优势吗?或者有什么替代方案?有什么可能的方法来处理这种情况?

在我的许多订阅者的情况下,异步事件的优点或替代方案

异步事件发布可以提供帮助,但也可能引发新问题。例如,当发布者触发事件的速度快于订阅者使用事件的速度时,会发生什么?实际上,您只是将问题从发布者陷入困境转移到了消费者陷入排队通知的困境。如果一些使用者需要UI线程,这可能会产生特别的问题,这可能意味着要进一步调度/排队事件。在最坏的情况下,您可能会陷入有效的死锁状态,线程池和/或消息泵中塞满了消息,以至于一切都慢到爬行。

对于您的特定应用程序,请考虑编译一个"更改项"列表并在每个更新周期后为整个集合发送一个事件是否更有意义。由于您有数千个项目,可能会经常更改,因此这可能会大大减少每个周期的事件回调次数。