【发布时间】:2020-02-12 23:11:39
【问题描述】:
我创建了一个简单的示例来理解 C# 中的 async/await。
class Program
{
static void Main(string[] args)
{
var t = BarAsync();
Console.WriteLine("Main");
}
private static async Task BarAsync()
{
Console.WriteLine("This happens before await");
int i = await QuxAsync();
Console.WriteLine("This happens after await. This result of await is " + i);
}
private static Task<int> QuxAsync()
{
int c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
c++;
}
Console.WriteLine("in the middle processing...");
return Task.FromResult(c);
}
}
所以程序首先打印This happens before await,然后计算返回方法中的值。然后打印结果。
看起来不错。我的问题是,因为 await 不会阻塞评估异步方法的线程。我的理解是如果异步需要很长时间它会返回到它的调用方法。
对于我的例子,因为 QuxAsync() 需要很长时间,代码
Console.WriteLine("Main");
没有被阻止,很快就会被评估。 我认为打印顺序应该是
This happens before await
Main
in the middle processing...
This happens after await. This result of await is 2147483647
但不是,为什么?
【问题讨论】:
-
QuxAsync中的任何内容都实际上是异步的,仅仅因为它被标记为异步,并不会使其异步。您的操作同步运行,这就是打印顺序如此的原因。 -
我无法解释您要问的这个确切原因,但我可以为
WebApi's解释一个场景 我仍然对在控制台应用程序中运行await / async代码有一个模糊的理解不必经常这样做。当我这样做时,我会使用Task.Result()来获得结果。无论如何,await Task<T>将允许当前线程执行被释放回线程池并让另一个线程使用它,一旦工作完成,任务调度程序然后分配相同的线程或如果.ConfigureAwait(false)是可用线程使用并继续工作。它确实阻塞了线程 -
async不代表并行,Task不代表线程。通过创建示例来学习是很棒的,但是如果您必须对所有未按您想象的方式发生的事情提出问题,那么您将走上一条漫长而痛苦的道路,我建议您先研究async and await。浏览stackoverflow并检查所有异步和等待标签/问题和答案。查看 Stephen Clearys 和 Stephen Toubs 的博客 -
@MickyD:并发和异步不是一回事;异步工作流不必是并发的。例如,考虑“按喇叭,然后异步等待一秒钟,然后打开门”的工作流,并且在异步等待期间可以在 10 毫秒内处理一条消息。您不需要第二个工作线程来实现此异步流程。
-
@Hello:实验是个好主意,特别是因为它表明你对异步有一些错误的想法。这是获得正确信念的好机会。我同意上面的建议,即您首先要多阅读。我还想在 GUI 应用程序中进行实验添加到该建议。控制台应用程序具有不寻常的异步工作流线程上下文,这可能会造成混淆。 GUI 应用程序可以更轻松地了解如何使用单线程实现异步工作流。
标签: c# async-await task-parallel-library