取消等待自己
Cancel awaiting itself
我有以下示例代码:
public static async Task Async()
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(500);
Stopwatch sw = Stopwatch.StartNew();
await RunThread(ExpensiveOperation, source.Token);
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
public static async Task RunThread(Action act, CancellationToken token)
{ //modify this method to handle cancelling the token during the following await
await Task.Run(act); //Task.Run(act, token) doesn't help
}
public static void ExpensiveOperation()
{
Thread.Sleep(1000); //simulates CPU expensive operation
}
现在,我如何修改 RunThread
方法以实际停止等待长任务,方法是注册被取消的任务,因此 return 在 500 毫秒之后,而不是等待实际完成ExpensiveOperation
?
您应该将令牌传递给操作本身,并时常检查它:
public static async Task RunThread(Action<CancellationToken> act, CancellationToken token)
{
await Task.Run(() => act(token), token);
}
public static void ExpensiveOperation(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
token.ThrowIfCancellationRequested();
Thread.Sleep(100);
}
}
您还将令牌传递给 Task.Run
,这样返回的 Task
就会知道它已被取消,而不仅仅是出错。
如果您无法从 ExpensiveOperation
内部取消(您无法更改代码,或者它实际上是异步操作而不是同步操作),则使用 WithCancellation
扩展方法:
static Task WithCancellation(this Task task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
public static async Task RunThread(Action act, CancellationToken token)
{
await Task.Run(act).WithCancellation(token);
}
请注意,这种方法实际上并没有取消操作,它只是让您的代码流表现得像取消操作一样。
我有以下示例代码:
public static async Task Async()
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(500);
Stopwatch sw = Stopwatch.StartNew();
await RunThread(ExpensiveOperation, source.Token);
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
public static async Task RunThread(Action act, CancellationToken token)
{ //modify this method to handle cancelling the token during the following await
await Task.Run(act); //Task.Run(act, token) doesn't help
}
public static void ExpensiveOperation()
{
Thread.Sleep(1000); //simulates CPU expensive operation
}
现在,我如何修改 RunThread
方法以实际停止等待长任务,方法是注册被取消的任务,因此 return 在 500 毫秒之后,而不是等待实际完成ExpensiveOperation
?
您应该将令牌传递给操作本身,并时常检查它:
public static async Task RunThread(Action<CancellationToken> act, CancellationToken token)
{
await Task.Run(() => act(token), token);
}
public static void ExpensiveOperation(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
token.ThrowIfCancellationRequested();
Thread.Sleep(100);
}
}
您还将令牌传递给 Task.Run
,这样返回的 Task
就会知道它已被取消,而不仅仅是出错。
如果您无法从 ExpensiveOperation
内部取消(您无法更改代码,或者它实际上是异步操作而不是同步操作),则使用 WithCancellation
扩展方法:
static Task WithCancellation(this Task task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
public static async Task RunThread(Action act, CancellationToken token)
{
await Task.Run(act).WithCancellation(token);
}
请注意,这种方法实际上并没有取消操作,它只是让您的代码流表现得像取消操作一样。