如果再次调用异步和正在运行的方法并且以前的调用结果已过时,如何正确取消该方法



我有一个相当笼统的问题,但有一个特定的用例。

在我的特定情况下,我有一个带有输入文本框的 UI,如果用户正在更改该输入框中的文本,则会向用户最终可能想要输入的内容显示一些建议。换句话说,输入框使用自动完成功能。建议是从 Web 服务请求的,因此此过程需要大量时间,用户可能已经再次更改了文本。因此,我想取消或停止仍在获取过时数据的进程,并且只获取该方法最近调用的结果。

因此,假设 View 类中OnTextChanged的方法正在调用该方法GetRecommendationsAsync。我的方法是简单地取消以前和过时的GetRecommendationsAsync调用,然后在取消该方法时不要在 UI 中执行任何操作。这里有一些我刚刚编写的最小代码(因此可能包含错误(来显示概念:

public async Task OnTextChangedAsync(string newText)
{
try
{
var recommendations = await GetLatestRecommendationsAsync(newText);
ShowRecommendations(recommendations);
}
catch(TaskCanceledException)
{
}
}
private Task<Recommendations[]> GetLatestRecommendationsAsync(string text)
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
if (string.IsNullOrWhiteSpace(text)) return null;
return GetRecommendationsAsync(text, _cancellationTokenSource.Token);
}

现在,我的问题是这是一种有效的方法还是有一些缺点? 此外,我想知道是否有一种通用的已知模式来处理取消因再次调用而过时的方法的通用情况? 使用信号量的掌声更好吗? 你会如何处理这个案子? 是否保证在新调用返回其结果之前捕获对先前调用的取消?

想知道

是否有一种通用的已知模式来处理取消因再次调用而过时的方法的通用情况?

取消令牌是处理出于任何原因的取消的一般已知模式。

是否保证在新调用返回其结果之前捕获对先前调用的取消?

不。这是因为取消令牌用于合作取消,这意味着一方请求取消,另一方定期检查取消请求并决定如何取消。这种方法的目的是确保任何需要撤消的操作都被撤消,并且您不会让事情处于不稳定状态。

相比之下,例如,在后台线程中执行工作并仅杀死线程以取消。你不知道它是在什么时候被杀死的,也不知道是否有任何东西处于潜在的未知或不稳定状态。

如果出于某种原因,您必须确保在已知前一次尝试停止之前甚至不会开始另一次尝试,那么您将不得不使用信号量之类的东西(可能与取消令牌一起(。这一切都取决于GetRecommendationsAsync在做什么。

旁注:OnTextChangedAsync的签名看起来很可疑。它的名称类似于事件,但事件必须返回void

最新更新