C#async /等待控制台应用程序中的奇怪行为

Jek*_*nic 8 .net c# asynchronous async-await c#-5.0

我构建了一些异步/等待演示控制台应用程序并得到奇怪的结果.码:

class Program
{
    public static void BeginLongIO(Action act)
    {
        Console.WriteLine("In BeginLongIO start... {0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(1000);
        act();
        Console.WriteLine("In BeginLongIO end... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
    }

    public static Int32 EndLongIO()
    {
        Console.WriteLine("In EndLongIO start... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(500);
        Console.WriteLine("In EndLongIO end... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        return 42;
    }

    public static Task<Int32> LongIOAsync()
    {
        Console.WriteLine("In LongIOAsync start... {0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        var tcs = new TaskCompletionSource<Int32>();
        BeginLongIO(() =>
        {
            try { tcs.TrySetResult(EndLongIO()); }
            catch (Exception exc) { tcs.TrySetException(exc); }
        });
        Console.WriteLine("In LongIOAsync end... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        return tcs.Task;
    }

    public async static Task<Int32> DoAsync()
    {
        Console.WriteLine("In DoAsync start... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        var res = await LongIOAsync();
        Thread.Sleep(1000);
        Console.WriteLine("In DoAsync end... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        return res;
    }

    static void Main(String[] args)
    {
        ticks = DateTime.Now.Ticks;
        Console.WriteLine("In Main start... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        DoAsync();
        Console.WriteLine("In Main exec... \t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(3000);
        Console.WriteLine("In Main end... \t\t{0} {1}", (DateTime.Now.Ticks - ticks) / TimeSpan.TicksPerMillisecond, Thread.CurrentThread.ManagedThreadId);
    }

    private static Int64 ticks;
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述

也许我不完全明白究竟是什么等待.我想如果执行到来等待执行返回到调用方法和任务等待在另一个线程中运行.在我的示例中,所有操作都在一个线程中执行,并且执行不会在await关键字之后返回到调用方法.真相在哪里?

i3a*_*non 2

这不是async-await工作原理。

将方法标记为async不会创建任何后台线程。当您调用一个async方法时,它会同步运行直到异步点,然后才返回给调用者。

异步点是当您的await任务尚未完成时。当它完成时,该方法的其余部分将被安排执行。该任务应该代表实际的异步操作(如 I/O 或Task.Delay)。

在您的代码中没有异步点,也没有返回调用线程的点。线程会越来越深入并阻塞,Thread.Sleep直到这些方法完成并DoAsync返回。

举个简单的例子:

public static void Main()
{
    MainAsync().Wait();
}

public async Task MainAsync()
{
    // calling thread
    await Task.Delay(1000);
    // different ThreadPool thread
}
Run Code Online (Sandbox Code Playgroud)

这里我们有一个实际的异步点(Task.Delay),调用线程返回到该点Main,然后同步阻塞该任务。一秒钟后,Task.Delay任务完成,方法的其余部分在不同的ThreadPool线程上执行。

如果Task.Delay我们不使用它Thread.Sleep,那么它将在同一个调用线程上运行。