【发布时间】:2021-02-25 16:36:11
【问题描述】:
我想取消重入时的异步功能,这样工作就不会堆积起来,并且可以防止不需要的工作。
例如我的文件扫描可能需要长达 8 秒,但是当我在 UI 中更改文件夹时,应该取消旧功能。
我看到了带有CancellationToken 的示例,但在我看来代码太多了。
我的方法是这样的,它似乎有效,但它给代码增加了很多混乱。
也许我也错过了TaskCanceledException,它会添加更多代码。
private CancellationTokenSource scanFilesState;
private IList<FileInfo> files;
private async Task ScanFilesAsync(string path)
{
// stop old running
this.scanFilesState?.Cancel();
this.scanFilesState?.Dispose();
this.scanFilesState = new CancellationTokenSource();
this.files = await FileHandler.ScanFilesAsync(path, this.scanFilesState.Token);
this.scanFilesState?.Dispose();
this.scanFilesState = null;
}
有没有更短或更好的方法?
是否有封装此代码的模式?
【问题讨论】:
-
您可以考虑将这种杂乱无章的功能封装在
CancelableExecution类中,并使用Task RunAsync(Func<CancellationToken, Task> action)公共 API。有一个实现here,由于对线程安全的额外要求,它有很多代码。在您的情况下,我猜您的所有代码都在 UI 线程上运行,因此可以使实现更简单。 -
好的,谢谢,这似乎是我需要的。很可能我在 UI 线程上运行,但不确定。为什么是评论而不是真正的回复帖子,所以我可以将其标记为答案?
-
在 GUI 应用程序中,
await之后的延续在 UI 线程上运行(除非您明确将其配置为不这样做),因此您不必担心一个线程取消CancellationTokenSource而另一个线程处理它。无论FileHandler.ScanFilesAsync内部发生什么,关于CTS 的处理都无关紧要。因此,花一些时间编写一个更简单的(单线程)实现是有意义的,您可以随意轻松地自定义它。 -
我之前的评论本质上只是一个指向现有答案的链接。恕我直言,它本身不值得回答。 :-)
-
取消是协作功能,它不会取消已经启动的任务,因为这会导致系统不稳定。 Task一旦启动,就没有停止过,你最多可以忽略它
标签: c# asynchronous cancellation-token reentrancy