取消长时间 运行 任务延迟
Cancelling a Long Running Task Delay
我正在尝试取消由网络 api 请求创建的异步延迟任务 (Task.Delay),另一个网络 api 请求发出取消请求。它看起来不像是取消了 task.delay 的计时器。这是我要实现的代码片段。为了您的信息,我正在使用 Application 对象存储 CancellationTokenSource 对象以跨多个请求检索令牌源。
更新 问题是我希望通过从代码中抛出异常来取消任务。但它从未发生过。如何使此代码取消 task.delay?
using Microsoft.Practices.Unity;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
namespace WebApplication8.Controllers
{
public class TaskController : ApiController
{
[HttpGet]
public async Task<string> CreateTask(int id)
{
var tokenSource = new CancellationTokenSource();
var concurrentTokens = GetConcurrentTokens();
concurrentTokens.TryAdd(id, tokenSource);
CancellationToken token = tokenSource.Token;
token.ThrowIfCancellationRequested();
await Task.Delay(50000,token);
return "Task Created";
}
[HttpGet]
public async Task<string> Cancel(int id)
{
var concurrentTokens = GetConcurrentTokens();
CancellationTokenSource item = concurrentTokens.First(t => t.Key == id).Value;
item.Cancel();
item.Dispose();
var tokenSource2 = new CancellationTokenSource();
concurrentTokens.TryRemove(id,out tokenSource2);
return "Cancelled";
}
private ConcurrentDictionary<long, CancellationTokenSource> GetConcurrentTokens()
{
var tokens = HttpContext.Current.Application["Tokens"];
if (tokens == null)
{
tokens = new ConcurrentDictionary<long, CancellationTokenSource>();
HttpContext.Current.Application["Tokens"] = tokens;
}
return (ConcurrentDictionary<long, CancellationTokenSource>) tokens;
}
}
}
我认为它被取消了,你可以通过像这样添加 try catch 来尝试它:
try
{
await Task.Delay(5000, token);
}
catch(TaskCanceledException ex)
{
}
你会看到它进入了 catch 块,这个方法没有任何作用 return 因为 TaskCanceledException
你的代码看起来是正确的,我是这样测试的:
var tc = new TaskController();
var backTask1 = tc.CreateTask(1);
var backTask2 = tc.CreateTask(2);
// task 2 gets cancelled
await tc.Cancel(2);
try
{
var res2 = await backTask2;
}
catch (OperationCanceledException) { }
// task 1 waits
await backTask1;
n.b。那:
token.ThrowIfCancellationRequested()
在您创建 CancellationTokenSource
之后什么都不做 - 如果某些代码已经取消了源,此方法实际上只是抛出异常。
- 如果任务在未等待的情况下启动,您将不会看到它引发的异常,直到它被等待。
尝试使用 TaskCompletionSource
。它对我有用,但我不确定这是否是您要找的。
var source = new CancellationTokenSource();
var concurrentTokens = GetConcurrentTokens();
concurrentTokens.TryAdd(id, source);
var completionSource = new TaskCompletionSource<object>();
source.Token.Register(() => completionSource.TrySetCanceled());
var task = Task.Delay(50000, source.Token);
// Continue when any of these are done.
await Task.WhenAny(task, completionSource.Task);
if (task.IsCanceled)
{
return "Task was not created";
}
return "Task Created";
此外,没有必要保留 Cancel
async
。您可以 return 一个字符串而不是 Task<string>
.
我正在尝试取消由网络 api 请求创建的异步延迟任务 (Task.Delay),另一个网络 api 请求发出取消请求。它看起来不像是取消了 task.delay 的计时器。这是我要实现的代码片段。为了您的信息,我正在使用 Application 对象存储 CancellationTokenSource 对象以跨多个请求检索令牌源。 更新 问题是我希望通过从代码中抛出异常来取消任务。但它从未发生过。如何使此代码取消 task.delay?
using Microsoft.Practices.Unity;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
namespace WebApplication8.Controllers
{
public class TaskController : ApiController
{
[HttpGet]
public async Task<string> CreateTask(int id)
{
var tokenSource = new CancellationTokenSource();
var concurrentTokens = GetConcurrentTokens();
concurrentTokens.TryAdd(id, tokenSource);
CancellationToken token = tokenSource.Token;
token.ThrowIfCancellationRequested();
await Task.Delay(50000,token);
return "Task Created";
}
[HttpGet]
public async Task<string> Cancel(int id)
{
var concurrentTokens = GetConcurrentTokens();
CancellationTokenSource item = concurrentTokens.First(t => t.Key == id).Value;
item.Cancel();
item.Dispose();
var tokenSource2 = new CancellationTokenSource();
concurrentTokens.TryRemove(id,out tokenSource2);
return "Cancelled";
}
private ConcurrentDictionary<long, CancellationTokenSource> GetConcurrentTokens()
{
var tokens = HttpContext.Current.Application["Tokens"];
if (tokens == null)
{
tokens = new ConcurrentDictionary<long, CancellationTokenSource>();
HttpContext.Current.Application["Tokens"] = tokens;
}
return (ConcurrentDictionary<long, CancellationTokenSource>) tokens;
}
}
}
我认为它被取消了,你可以通过像这样添加 try catch 来尝试它:
try
{
await Task.Delay(5000, token);
}
catch(TaskCanceledException ex)
{
}
你会看到它进入了 catch 块,这个方法没有任何作用 return 因为 TaskCanceledException
你的代码看起来是正确的,我是这样测试的:
var tc = new TaskController();
var backTask1 = tc.CreateTask(1);
var backTask2 = tc.CreateTask(2);
// task 2 gets cancelled
await tc.Cancel(2);
try
{
var res2 = await backTask2;
}
catch (OperationCanceledException) { }
// task 1 waits
await backTask1;
n.b。那:
token.ThrowIfCancellationRequested()
在您创建CancellationTokenSource
之后什么都不做 - 如果某些代码已经取消了源,此方法实际上只是抛出异常。- 如果任务在未等待的情况下启动,您将不会看到它引发的异常,直到它被等待。
尝试使用 TaskCompletionSource
。它对我有用,但我不确定这是否是您要找的。
var source = new CancellationTokenSource();
var concurrentTokens = GetConcurrentTokens();
concurrentTokens.TryAdd(id, source);
var completionSource = new TaskCompletionSource<object>();
source.Token.Register(() => completionSource.TrySetCanceled());
var task = Task.Delay(50000, source.Token);
// Continue when any of these are done.
await Task.WhenAny(task, completionSource.Task);
if (task.IsCanceled)
{
return "Task was not created";
}
return "Task Created";
此外,没有必要保留 Cancel
async
。您可以 return 一个字符串而不是 Task<string>
.