异步方法在同一个线程上运行,没有时间延迟

Exp*_*ice 0 .net c# multithreading async-await

这是AsyncMethods类看起来像:

public class AsyncMethods
{
    public static async Task<double> GetdoubleAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return 80d;
    }
    public static async Task<string> GetStringAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return "async";
    }
    public static async Task<DateTime> GetDateTimeAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return DateTime.Now;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要方法:

static void Main(string[] args)
{
    while (Console.ReadLine() != "exit")
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        DateTime dt = DateTime.Now;
        var res = GetStuffAsync().Result;
        var ts = DateTime.Now - dt;
        Console.WriteLine(res);
        Console.WriteLine("Seconds taken: " + ts.Seconds + " milliseconds taken: " + ts.Milliseconds);
    }
    Console.ReadLine();
    return;
}
static async Task<object> GetStuffAsync()
{
    var doubleTask = AsyncMethods.GetdoubleAsync();
    var StringTask = AsyncMethods.GetStringAsync();
    var DateTimeTask = AsyncMethods.GetDateTimeAsync();

    return new
    {
        _double = await doubleTask,
        _String = await StringTask,
        _DateTime = await DateTimeTask,
    };
}
Run Code Online (Sandbox Code Playgroud)

从每种方法中可以看出,我增加了1秒的延迟.这是输出:

Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
{ _double = 80, _String = async, _DateTime = 2/15/2017 4:32:00 AM }
Seconds taken: 1 milliseconds taken: 40

Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
{ _double = 80, _String = async, _DateTime = 2/15/2017 4:32:03 AM }
Seconds taken: 1 milliseconds taken: 16
Run Code Online (Sandbox Code Playgroud)

现在我有两个问题:

  1. 为什么一切都发生在一个线程上?
  2. 当我等了3秒钟时,为什么延迟只有1秒?

Eri*_*ert 12

首先:如果您有两个问题,请提出两个问题.不要在一个问题中提出两个问题.

为什么一切都发生在一个线程上?

这是一个错误的问题.正确的问题是:为什么你认为任何事情都应该在第二个线程上发生?

在这里,我会给你一个任务:等五分钟,然后检查你的电子邮件.在你等待的时候,做一个三明治.您是否需要雇人才能做等待或制作三明治?显然不是.线程是工人.如果工作可以由一名工人完成,则无需雇用工人.

如果你不需要,最重要的await避免使用额外的线程.在这种情况下,您不需要.

当我等了3秒钟时,为什么延迟只有1秒?

比较这两个工作流程.

  • 等五分钟; 在你等待的时候,做一个三明治
  • 然后检查你的邮箱
  • 然后等五分钟; 在你等待的时候,做一个三明治
  • 然后检查你的邮箱
  • 然后等五分钟; 在你等待的时候,做一个三明治
  • 然后检查你的邮箱

如果您执行该工作流程,您将等待总共十五分钟.

您编写的工作流程是:

  • 等五分钟
  • 同时,等五分钟
  • 同时,等五分钟
  • 在你等待的时候,做一个三明治
  • 然后检查你的邮箱

您只需等待五分钟即可完成该工作流程; 所有延迟都在同一时间发生.

你看到你现在如何错误地编写你的程序了吗?

这里要理解的关键洞察是等待是程序中的一个点,其中await的延续被延迟到等待任务完成之后.

如果您没有等待,程序将自行继续,无需等待.那是意思await.

  • @ExpertNovice:现在,*continuations*可能被安排到不同的线程的事实是你正在构建一个控制台应用程序的结果.控制台应用程序没有用于协调异步任务的消息循环,因此在某些情况下,控制台应用程序被强制将延续分配给其他线程.如果您要编写WPF或WinForms程序,您会看到异步延续在UI线程上恢复.如果您正在学习异步,请不要编写控制台应用程序.编写GUI应用程序. (2认同)