在 WPF 应用程序中,我有一个通过网络接收消息的类。每当所述类的对象收到完整消息时,就会引发一个事件。在应用程序的 MainWindow 中,我有一个订阅该事件的事件处理程序。保证在应用程序的 GUI 线程上调用事件处理程序。
每当调用事件处理程序时,都需要将消息的内容应用于模型。这样做可能会非常昂贵(在当前硬件上 > 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 事件处理程序重入的明智方法吗?
编辑:删除了不必要的await this.pending;
语句OnMessageReceived
。
编辑 2:消息必须以与接收消息相同的顺序应用于模型。