如果异步方法是单线程的,它如何在后台运行?

本文关键字:后台 运行 异步方法 单线程 如果 | 更新日期: 2023-09-27 17:51:08

我正在尝试理解async/await,并且已经阅读了许多文章,但我仍然对同步/异步的性质感到困惑。

我有以下测试控制台应用程序:

static void Main(string[] args)
{
    var test = FooAsync();
    Console.WriteLine("After FooAsync");
    for (int i = 0; i < 100; i++)
        Console.WriteLine("After that");
    Console.ReadKey();
}
private static async Task FooAsync()
{
    Console.WriteLine("Before delay");
    await Task.Delay(1);
    Console.WriteLine("After delay");
}

代码给出如下输出:

Before delay
After FooAsync
After that
After that
After that
After that
After delay
After that
.
.

我理解async/await将创建一个单独的线程进行处理,并且在FooAsync到达await Task.Delay(1)行时,它将返回Main,因为任务尚未完成,然而,由于我们只在单个线程上运行,有人可以解释是什么触发FooAsync方法在Main内的任意点恢复,然后Main可以继续?

我收回它,我认为arnon和dariogriffo是正确的。代码确实使用了多个线程(正如我之前在调试器中看到的那样,或者像kha建议的那样做)。我对下面页面https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads上的线程部分感到困惑,没有意识到"延续"实际上指的是在"等待"任务完成后立即运行的延续任务计划。

如果异步方法是单线程的,它如何在后台运行?

这不是单线程

当延迟任务完成时,方法的其余部分被发布到ThreadPool并与主线程并发运行。这里的"触发器"是在Task.Delay内部使用的内部System.Threading.Timer的回调。

此行为取决于SynchronizationContext。在UI环境中,这将被发布到相同的UI线程,并且必须等待,直到该线程空闲。

如果您一直在等待从FooAsync 返回的任务,那么您每次只会有一个线程运行

Async/await是否会创建新线程,这取决于操作的性质。如果操作是IO(例如磁盘/网络操作),则可能以一种不会旋转新线程的方式编码。你可以从这里阅读:

async和await关键字不会导致创建额外的线程吗?

如果你创建了自己的Async操作并创建了一个线程,那就是另一回事了,这就是为什么你不应该在sync之上使用Async

http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

你也可以检查这个,但使用线程。CurrentThread获取进程的Id。(添加到Console.WriteLine)

认为asyncawait关键字创建新线程是一个非常普遍的误解。他们没有。

线程是通过运行Task创建的。在本例中,线程是由Task.Delay调用创建的。