如果收到新请求,如何取消先前的任务?
Posted
技术标签:
【中文标题】如果收到新请求,如何取消先前的任务?【英文标题】:How to cancel previous Task if new request recieved? 【发布时间】:2015-07-03 10:58:10 【问题描述】:我将尝试在这里简化我的情况,使其更加简洁明了。因此,我正在开发一个 WinRT 应用程序,其中用户在 TextBox
和其 TextChanged
事件中输入文本 2 秒后我需要发出远程请求以根据用户获取数据文本。
现在用户输入文本并且网络请求已被初始化,但用户立即写入另一个术语。所以,我需要取消第一个 Web 请求并触发新的请求。
考虑以下作为我的代码:
private CancellationTokenSource cts;
public HomePageViewModel()
cts = new CancellationTokenSource();
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
//Cancel previous request before making new one
//GetMembers() is using simple HttpClient to PostAsync() and get response
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
我知道CancellationToken
在这里发挥作用,但我就是不知道如何。
【问题讨论】:
【参考方案1】:你已经差不多了。核心思想是单个CancellationTokenSource
只能取消一次,所以每次操作都要创建一个新的。
private CancellationTokenSource cts;
private async void SearchPeopleTextChangedHandler(SearchPeopleTextChangedEventArgs e)
// If there's a previous request, cancel it.
if (cts != null)
cts.Cancel();
// Create a CTS for this request.
cts = new CancellationTokenSource();
try
var members = await _myService.GetMembers(someId, cts.Token);
//other stuff based on members
catch (OperationCanceledException)
// This happens if this operation was cancelled.
【讨论】:
是否需要处理 CancellationTokenSource?对 _myService.GetMembers 的调用是否应该在完成后立即发生,这样我们就不会取消不再需要的先前令牌? @bmadtiger:CancellationTokenSource
应该被取消或处置。由于我们总是取消旧的,因此不需要处理。处理 CancellationTokenSource
s 可能会很麻烦,因为它会导致一些成员抛出异常。
感谢@stephen-cleary - 我一直在尝试同时执行Cancel
和Dispose
并在短时间内收到大量重复调用的异常,因为CancellationTokenSource
已经被处理了.这或许可以解释。【参考方案2】:
我会像这样实现GetMembers
方法:
private async Task<List<Member>> GetMembers(int id, CancellationToken token)
try
token.ThrowIfCancellationRequested();
HttpResponseMessage response = null;
using (HttpClient client = new HttpClient())
response = await client.PostAsync(new Uri("http://apiendpoint"), content)
.AsTask(token);
token.ThrowIfCancellationRequested();
// Parse response and return result
catch (OperationCanceledException ocex)
return null;
其余的只是调用cts.Cancel()
方法并创建CancellationTokenSource
的新实例,然后每次在处理程序中调用GetMembers
。当然,正如@Russell Hickey 提到的,cts
应该是全球性的。 (如果该类有多个实例,并且您总是希望在调用此处理程序时取消 GetMembers
方法,则甚至是静态的。通常我还有一个包装结果的类,并有一个附加属性 IsSuccessful
来区分真正的null
操作失败的结果。
【讨论】:
以上是关于如果收到新请求,如何取消先前的任务?的主要内容,如果未能解决你的问题,请参考以下文章