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

时间:2015-05-29 10:33:21

标签: c# .net multithreading asynchronous async-await

我正在尝试理解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)行时它将返回{{1但是,因为我们只在单个线程上运行,所以有人可以解释是什么触发Main方法在FooAsync Main之前的任意点恢复然后可以继续?

更新 我把它拿回来,i3arnon和dariogriffo是正确的。代码确实使用了多个线程(正如我之前看到的那样,在调试器中查看或完成了kha建议的显而易见的事情)。我对下一页https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads中的“线程”部分感到困惑,没有意识到“延续”实际上是指一旦“等待”任务完成就会继续运行的延续任务计划。

3 个答案:

答案 0 :(得分:5)

这不是单线程

当延迟任务完成时,方法的其余部分将发布到ThreadPool并与主线程同时运行。 &#34;触发&#34;这是System.Threading.Timer内部使用的内部Task.Delay的回调。

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

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

答案 1 :(得分:2)

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

The async and await keywords don't cause additional threads to be created?

如果您创建自己的异步操作并创建了一个线程,这是一个不同的故事,这就是为什么您不应该执行同步异步

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

您也可以检查这一点,但使用Thread.CurrentThread来获取进程的ID。 (将其添加到Console.WriteLine)

答案 2 :(得分:0)

asyncawait关键字创建新线程是一种非常常见的误解。他们没有。

通过运行Task创建线程。在这种情况下,线程由Task.Delay调用创建。