在我当前的项目中,我有一段代码,在将其简化到遇到问题的地方后,看起来像这样:
private async Task RunAsync(CancellationToken cancel)
{
bool finished = false;
while (!cancel.IsCancellationRequested && !finished)
finished = await FakeTask();
}
private Task<bool> FakeTask()
{
return Task.FromResult(false);
}
如果我不等待就使用此代码,无论如何我最终都会阻塞:
// example 1
var task = RunAsync(cancel); // Code blocks here...
... // Other code that could run while RunAsync is doing its thing, but is forced to wait
await task;
// example 2
var task = RunAsync(cancelSource.Token); // Code blocks here...
cancelSource.Cancel(); // Never called
在实际的项目中,我实际上并没有使用FakeTask,通常会在其中等待一些Task.Delay,因此大部分时间代码实际上并没有阻塞,或者仅在有限的迭代次数内。
但是,在单元测试中,我使用的模拟对象执行FakeTask的大部分工作,因此,当我想查看RunAsync是否响应其CancellationToken取消了我期望的取消方式时,我陷入了困境。
我发现我可以通过在RunAsync的顶部添加例如
await Task.Delay(1)
来解决此问题,以强制它真正地异步运行,但这感觉有些棘手。有更好的选择吗? 最佳答案
Task.FromResult
实际上与await Task.Delay(0)
同步运行。如果要实际模拟异步代码,请调用Task.Yield()
。这将创建一个等待的任务,等待时异步地返回当前上下文。
关于c# - 异步方法阻止未完成的任务,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55243987/