在我当前的项目中,我有一段代码,在将其简化到遇到问题的地方后,看起来像这样:

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/

10-14 12:14