在一个WPF应用程序中,我有一个类可以通过网络接收消息。每当该类的一个对象接收到完整的消息时,就会引发一个事件。在应用程序的MainWindow中,我订阅了该事件的事件处理程序。保证在应用程序的GUI线程上调用事件处理程序。
每当调用事件处理程序时,需要将消息内容应用于模型。这样做可能非常耗费时间(在当前硬件上大约超过200毫秒)。因此,使用Task.Run将应用程序从主线程中卸载到线程池中。
现在,由于可以连续地接收消息,因此在仍在处理先前更改时可能会调用事件处理程序。确保消息仅一次应用的最简单方法是什么?到目前为止,我想到了以下方法:
每当调用事件处理程序时,需要将消息内容应用于模型。这样做可能非常耗费时间(在当前硬件上大约超过200毫秒)。因此,使用Task.Run将应用程序从主线程中卸载到线程池中。
现在,由于可以连续地接收消息,因此在仍在处理先前更改时可能会调用事件处理程序。确保消息仅一次应用的最简单方法是什么?到目前为止,我想到了以下方法:
using System;
using System.Threading.Tasks;
using System.Windows;
public partial class MainWindow : Window
{
private Model model = new Model();
private Task pending = Task.FromResult<bool>(false);
// Assume e carries a message received over the network.
private void OnMessageReceived(object sender, EventArgs e)
{
this.pending = ApplyToModel(e);
}
private async Task ApplyToModel(EventArgs e)
{
await this.pending;
await Task.Run(() => this.model.Apply(e)); // Assume this is an expensive call.
}
}
这看起来能够正常工作,但它似乎会产生"内存泄漏",因为应用消息的任务总是会首先等待应用前一个消息的任务。如果是这样的话,那么以下更改应该可以避免内存泄漏:
private async Task ApplyToModel(EventArgs e)
{
if (!this.pending.IsCompleted)
{
await this.pending;
}
await Task.Run(() => this.model.Apply(e));
}
这是一种避免异步 void 事件处理程序重入的明智方式吗?
编辑:在 OnMessageReceived
中删除不必要的 await this.pending;
语句。
编辑 2:消息必须以接收到的相同顺序应用于模型。