【问题标题】:Is there a reliable way to stop a thread without using Cancel?有没有一种可靠的方法可以在不使用取消的情况下停止线程?
【发布时间】:2019-10-25 19:23:26
【问题描述】:

我的情况似乎与大多数人的需要相反。我不需要阻塞线程,也没有看到“合作取消”这件事的好方法。

我有一个UserControl,上面有一个网格控件。该网格的选择用于通知同一UserControl 上的详细信息面板。当用户选择行时,会有一个async 获取相关记录。有时,该提取所需的时间比用户选择不同行所需的时间长,从而导致该新行的线程提取。当用户在网格中从一行移动到另一行时,这会重复。例如,他们可以使用箭头键,这样他们就可以快速地从一行移动到另一行。

我无法阻止线程,因为我需要获取当前选定行的数据。相反,我需要一种有效的方法来立即停止之前的尝试。否则,这些获取会堆积起来,如果相关数据足够大,我有时甚至会得到OutOfMemoryExceptions

这是基本思想和示例:

用户单击网格行,绑定属性触发一个获取详细数据的方法,其中包括对相关项目的获取调用:

private ObservableCollection<DataRecord> _currentData = null;
public ObservableCollection<DataRecord> CurrentData
{
    get => _currentData;
    set => SetProperty(ref _currentData, value, () => CurrentData);
}

public DataRecord SelectedRecord
{
    get => _selectedRecord;
    set
    {
        SetProperty(ref _selectedRecord, value, () => SelectedRecord);
        FetchDataAsync();
    }
}

public async void FetchDataAsync()
{
    CurrentData?.Clear();
    var dataList = await System.Threading.Tasks.Task.Run(() => GetDataList());
    CurrentData = dataList.ToObservableCollection();
}

private List<DataRecord> GetDataList()
{
    var dataList = new List<DataRecord>();
    using (var context = new DataContext(new DbFactory().GetConnectionString()))
        dataList = context.MyDataTable.Where(x => x.ID == SelectedRecord.ID).ToList();
    return dataList;
}

GetDataList() 方法中真正起作用的唯一行是从数据库中获取数据,因此没有好地方可以查找取消标志。

我想知道我使用公共集合作为这些返回记录集的最终目的地是否是问题的一部分?

【问题讨论】:

  • 使请求一直异步并传递CancellationToken。当用户更改他们的选择时取消令牌。
  • 可靠的方法是使用 CancellationToke。 async void 不应该被使用,除了事件处理程序,这意味着FetchDataAsync 有一个坏的错误。 async void 不能等待,运行时对这些任务一无所知,当它们运行时,它们尝试访问的对象可能已经被释放
  • 停止使用 linq 的循环并自己制作,然后你有很多地方可以取消。每次迭代一次。
  • 您使用的是什么 ORM? EF 有 ToListAsync 这意味着不需要 Task.Run 和 GetDataList()。您也不需要ToObservableCollection 来设置属性并引发通知事件。 ObservableCollection 仅在您想要修改集合时需要
  • PS:WPF 有延迟绑定。也许您需要做的就是将Delay 添加到您的绑定中。检查Rick Strahl's article on Debouncing 其中还提到了Text="{Binding TopicsFilter,UpdateSourceTrigger=PropertyChanged,Delay=500}"

标签: c# wpf async-await


【解决方案1】:

没有办法“立即停止”和不支持立即停止或取消的操作。您的 GetDataList() 方法没有。一旦被调用,它将一直运行,直到完成或引发异常。

此外,属性设置器不应启动异步操作:https://blog.stephencleary.com/2013/01/async-oop-3-properties.html

您可以在这里为SelectedRecord 属性处理PropertyChanged 事件,取消当前正在执行的任何任务并启动另一个任务。

任务完成后,您需要确定结果是否仍然准确,或者自任务开始后是否做出了新的选择。如果是后者,您可以丢弃结果并等待最后一个。

解决此问题的另一种选择是使用像 ReactiveUI 这样支持响应式和可组合属性的库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    • 2011-09-30
    相关资源
    最近更新 更多