c# - 异步方法阻塞未等待的任务

标签 c# .net asynchronous async-await

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

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) 来解决这个问题,以强制它真正异步运行,但这感觉有点老套。有更好的选择吗?

最佳答案

您对 await 的作用有一个不正确的印象。 await的含义是:

  • 检查可等待对象是否完整。如果是,则获取其结果并继续执行协程。
  • 如果未完成,则将当前方法的剩余部分注册为等待对象的延续,并通过将控制权返回给调用者来挂起协程。 (请注意,这使其成为一个半协程。)

在你的程序中,“假”等待总是完成的,所以协程永远不会挂起。

Are there better alternatives?

如果您的控制流逻辑要求您暂停协程,则使用 Task.Yield

关于c# - 异步方法阻塞未等待的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55243987/

相关文章:

c# - 在 Windows 环境与 Ubuntu 环境中执行 "dotnet lambda package"的不同包

c# - 数据聚类方法

发布项目时用 EXE 打包支持文件的 C# 问题

.net - 在从网络共享运行的应用程序的 UAC 提升提示上显示应用程序图标

c# - 为什么我可以将 COM 对象转换为错误的接口(interface)?

c++ - WriteFile() block (通过命名管道从 C++ 客户端写入到 C# 服务器)

asynchronous - 在Dart中以同步方式调用异步功能

c# - 未处理的异常 : System. AccessViolationException:尝试读取或写入

c# - 中止包含永无止境的库方法的任务(无法检查取消请求)

C# 如何解决 HtppWebResponse return Could not establish trust relationship for the [SSL/TLS] secure channel?