IO绑定异步工作所需的线程数

Big*_* AL 0 c# asynchronous async-await

TL; DR: 是否可以仅使用一个线程启动一系列IO绑定任务async await

简而言之: 努力学习async await.在本视频("C#和Visual Basic的异步最佳实践")中,演讲者举例说明了async await如何启动一些IO绑定工作.他明确地说(在21分40秒)同时解释了为什么并行for循环不是最佳的,因为它们耗尽了线程的负载:

我们不需要更多线程.我们不需要两个线程......

我们真的可以在不使用多个线程的情况下异步启动多个请求吗?怎么样?不幸的是,发言人没有提供所有的代码,所以这是我的努力:

// Pretty much exactly the same as video
private async Task<List<string>> LoadHousesAsync()
{
    // Running on the UI thread
    Debug.Print("Thread: " + Thread.CurrentThread.ManagedThreadId);
    var tasks = new List<Task<string>>();

    for (int i = 0; i < 5; i++)
    {
        Task<string> t = LoadHouseAsync(i);
        tasks.Add(t);
    }

    string[] loadedHouses = await Task.WhenAll(tasks);
    return loadedHouses.ToList();
}

// My guess of the LoadHouseAsync method
private Task<string> LoadHouseAsync(int i)
{
    // Running on the UI thread
    Debug.Print("Thread: " + Thread.CurrentThread.ManagedThreadId);
    return Task.Run(() => LoadHouse(i));
}

// My guess of the LoadHouse method
private string LoadHouse(int i)
{
    // **** This is on a different thread  :(  ****
    Debug.Print("Thread: " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(5000); // simulate I/O bound work
    return "House" + i;
}
Run Code Online (Sandbox Code Playgroud)

这是输出.

Thread: 10
Thread: 10
Thread: 3
Thread: 10
Thread: 10
Thread: 11
Thread: 10
Thread: 12
Thread: 10
Thread: 13
Thread: 14
Run Code Online (Sandbox Code Playgroud)

Jak*_*rtz 6

您可以使用异步I/O执行此操作.你做的是做错的一个非常好的例子(不幸的是,它也很常见).

Task.Run在线程池线程上运行一个方法,Thread.Sleep阻塞该线程.因此,您的示例模拟在多个线程上执行同步(阻塞)I/O.

要正确执行异步I/O,您需要始终使用异步方法.永远不要Task.Run用于I/O. 您可以使用Task.Delay以下方法模拟异步I/O方法:

private async Task<string> LoadHouseAsync(int i)
{
    Debug.Print("Thread: " + Thread.CurrentThread.ManagedThreadId);
    await Task.Delay(5000); // simulate async I/O bound work
    return "House" + i;
}
Run Code Online (Sandbox Code Playgroud)