如何取消异步任务?
How to cancel an asynchronous Task?
我有一个加载数据的方法,例如:
public async GetCustomers()
{
await Task.Run(() => {
for (int i = 0; i < 99; i++)
customers = customerRequest.GetCustomers();
});
}
customerRequest
是一个简单的 class,它使用 HttpClient
连接到 WebApi 服务器。调用栈如下:
method->request->controller action->server layer->repository->db
目前,控制器操作 returns IHttpActionResult
,而服务和存储层 return IEnumerable<Customer>
。同步调用所有方法。
出于测试目的,我添加了 for
循环以增加任务的延迟并查看正在执行的 SQL 语句。
如果用户决定关闭表单,任务仍在后台执行,SQL 语句仍会发送到数据库。
取消此类任务的正确方法是什么?
签出 CancellationTokenSource。您可以保留其中一个长期存在的按钮或关闭事件调用 Cancel()。如果您希望所有任务都取消,则只需要将其传递给所有任务即可。该任务将抛出异常,因此请确保包装在 try catch 中。您也可以查看您的任务中是否有取消请求,尝试优雅地闯关。
var cts = new CancellationTokenSource();
await Task.Run(() =>
{
//do work, will throw if cts.Cancel() is called
}, cts.Token);
//wait 2 seconds then cancel
await Task.Delay(2000);
cts.Cancel();
您想使用 CancellationTokenSource
,并将其 CancellationToken
传递到您的方法中。当表单关闭时,调用 CancellationTokenSource.Cancel
.
但是请注意,您希望将 CancellationToken
传递给实际使用它的方法。正如我在我的博客中所描述的那样,Task.Run
is not one of them.
你真正想要做的是从最低级别(在客户端)开始,然后将 CancellationToken
传递给你正在使用的任何 HttpClient
方法(即 like this one).
然后继续努力。我还建议让您的代码异步。完成后,您应该得到如下所示的 GetCustomers
:
public async Task GetCustomersAsync(CancellationToken token)
{
for (int i = 0; i < 99; i++)
customers = await customerRequest.GetCustomersAsync(token);
}
如果您想真正确定 (tm) 没有虚假请求发出,您还可以在执行请求之前明确检查令牌:
public async Task GetCustomersAsync(CancellationToken token)
{
for (int i = 0; i < 99; i++)
{
token.ThrowIfCancellationRequested();
customers = await customerRequest.GetCustomersAsync(token);
}
}
如果这对你很重要,你也可以handle cancellation on the server side。
我有一个加载数据的方法,例如:
public async GetCustomers()
{
await Task.Run(() => {
for (int i = 0; i < 99; i++)
customers = customerRequest.GetCustomers();
});
}
customerRequest
是一个简单的 class,它使用 HttpClient
连接到 WebApi 服务器。调用栈如下:
method->request->controller action->server layer->repository->db
目前,控制器操作 returns IHttpActionResult
,而服务和存储层 return IEnumerable<Customer>
。同步调用所有方法。
出于测试目的,我添加了 for
循环以增加任务的延迟并查看正在执行的 SQL 语句。
如果用户决定关闭表单,任务仍在后台执行,SQL 语句仍会发送到数据库。
取消此类任务的正确方法是什么?
签出 CancellationTokenSource。您可以保留其中一个长期存在的按钮或关闭事件调用 Cancel()。如果您希望所有任务都取消,则只需要将其传递给所有任务即可。该任务将抛出异常,因此请确保包装在 try catch 中。您也可以查看您的任务中是否有取消请求,尝试优雅地闯关。
var cts = new CancellationTokenSource();
await Task.Run(() =>
{
//do work, will throw if cts.Cancel() is called
}, cts.Token);
//wait 2 seconds then cancel
await Task.Delay(2000);
cts.Cancel();
您想使用 CancellationTokenSource
,并将其 CancellationToken
传递到您的方法中。当表单关闭时,调用 CancellationTokenSource.Cancel
.
但是请注意,您希望将 CancellationToken
传递给实际使用它的方法。正如我在我的博客中所描述的那样,Task.Run
is not one of them.
你真正想要做的是从最低级别(在客户端)开始,然后将 CancellationToken
传递给你正在使用的任何 HttpClient
方法(即 like this one).
然后继续努力。我还建议让您的代码异步。完成后,您应该得到如下所示的 GetCustomers
:
public async Task GetCustomersAsync(CancellationToken token)
{
for (int i = 0; i < 99; i++)
customers = await customerRequest.GetCustomersAsync(token);
}
如果您想真正确定 (tm) 没有虚假请求发出,您还可以在执行请求之前明确检查令牌:
public async Task GetCustomersAsync(CancellationToken token)
{
for (int i = 0; i < 99; i++)
{
token.ThrowIfCancellationRequested();
customers = await customerRequest.GetCustomersAsync(token);
}
}
如果这对你很重要,你也可以handle cancellation on the server side。