【发布时间】:2022-01-30 11:55:41
【问题描述】:
所以我遇到了第三方库的问题,即使在调用 cancellationToken.Cancel 时,调用也可能会卡住并且永远不会返回。下面是一个原型,它可以处理这种情况并且它可以工作。
public async Task MainAsync()
{
try
{
await StartAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine("Exception thrown");
}
}
private async Task<string> StartAsync()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(3 * 1000);
var tcs = new TaskCompletionSource<string>();
cts.Token.Register(() => { Console.WriteLine("Cancelled"); tcs.TrySetCanceled(); });
return await (await Task.WhenAny(tcs.Task, LongComputationAsync())
.ConfigureAwait(false)).ConfigureAwait(false);
}
private async Task<string> LongComputationAsync()
{
await Task.Delay(1 * 60 * 1000).ConfigureAwait(false);
return "Done";
}
因此,Above 将等待 3 秒,它会抛出一个 TaskCancelledException 就像它应该的那样。
如果您随后将方法 LongComputationAsync 更改为以下内容:
private Task<string> LongComputationAsync()
{
Task.Delay(1 * 60 * 1000).ConfigureAwait(false).GetAwaiter().GetResult();
return Task.FromResult("Done");
}
我仍然希望它具有相同的行为,但它的作用是,它将等待整整 1 分钟(在 LongComputationAsync() 中指定)然后抛出 TaskCancelledException。
谁能给我解释一下?关于这是如何工作的,或者这是否是开始时的正确行为。
【问题讨论】:
-
嗯,当然可以。如果您阻塞调用线程,
LongCompuationAsync不是异步的,它会阻塞调用线程 1 分钟。当StartAsync调用LongCompuationAsync时,它会卡在那条线上,直到1 分钟过去它甚至都不会到达第一个await。 -
特别是对
LongComputationAsync的调用在您同步等待的1 分钟延迟之后才会返回,因此您基本上最终会调用WhenAny来完成任务。
标签: c# async-await task-parallel-library .net-5