C# 中的异步 Main 和阻止异步 Http 调用

async Main in C# and blocking async Http calls

我对从我认为是纯异步程序中得到的输出感到很困惑。 如您所见,没有明显的反模式(我希望如此)和阻塞调用。

slowURL 限制服务器响应 10 秒。我确实通过 运行 以 10 秒超时调用本地服务器确认当 运行 控制台中的代码时 FetchSlowAsync 方法调用有效地阻塞主线程 10 秒。

我预计 TaskScheduler 不会按顺序安排调用,而是始终随机确定方法调用顺序。唉,输出总是确定的。

FetchSlowAsync start
FetchSlowAsync got data!
FetchAsync start
FetchAsync got data!
FetchBingAsync start
FetchBingAsync got data!
All done!

我的问题是:是什么提示 FetchSlowAsync 阻止而不是 TaskScheduler 执行上下文切换到另一个异步方法并在完成后返回它?

前者之后的下一个问题:为什么在异步执行模型是并发的情况下,async Main 中的所有方法的执行顺序与它们被调用的顺序相同?

using static System.Console;
using System.Net.Http;
using System.Threading.Tasks;

class Start
{
    const string serviceURL = "https://google.com";
    const string slowDown = "http://slowwly.robertomurray.co.uk/delay/10000/url/";
    const string slowURL = slowDown + serviceURL;
    const string OkURL = serviceURL;

    static async Task FetchSlowAsync()
    {
        await Console.Out.WriteLineAsync("FetchSlowAsync start");
        await new HttpClient().GetStringAsync(slowURL); //BLOCKS MAIN THREAD FOR 10 seconds        
        await Console.Out.WriteLineAsync("FetchSlowAsync got data!");
    }

    static async Task FetchAsync()
    {
        await Console.Out.WriteLineAsync("FetchAsync start");
        await new HttpClient().GetStringAsync(OkURL);
        await Console.Out.WriteLineAsync("FetchAsync got data!");        
    }

    static async Task FetchBingAsync()
    {
        await Console.Out.WriteLineAsync("FetchBingAsync start");
        await new HttpClient().GetStringAsync("https://bing.com");
        await Console.Out.WriteLineAsync("FetchBingAsync got data!");
    }

    static async Task Main()
    {
        await FetchSlowAsync();
        await FetchBingAsync();
        await FetchAsync();

        await System.Console.Out.WriteLineAsync("All done!");
    }
}

目前,您正在等待从 FetchSlowAsync() 返回的任务完成,然后再继续调用 FetchBingAsync 等。您正在等待任务,在这里:

await FetchSlowAsync();
await FetchBingAsync();
await FetchAsync();

如果你不想等slow fetch完成再开始Bing fetch等,你可以记住他们返回的任务,稍后再等待:

static async Task Main()
{
    // Start all three tasks
    Task t1 = FetchSlowAsync();
    Task t2 = FetchBingAsync();
    Task t3 = FetchAsync();

    // Then wait for them all to finish
    await Task.WhenAll(t1, t2, t3);

    await Console.Out.WriteLineAsync("All done!");
}

现在 你得到了我认为你期望的那种输出。例如,我的机器上有一个 运行:

FetchSlowAsync start
FetchBingAsync start
FetchAsync start
FetchAsync got data!
FetchBingAsync got data!
FetchSlowAsync got data!
All done!