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

时间:2015-11-19 00:43:09

标签: c# asynchronous async-await

TL; DR: 是否可以使用async await

仅使用一个线程启动一系列IO绑定任务

不太简短: 试着学习async await。在this video(“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;
}

这是输出。

Thread: 10
Thread: 10
Thread: 3
Thread: 10
Thread: 10
Thread: 11
Thread: 10
Thread: 12
Thread: 10
Thread: 13
Thread: 14

2 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

  

我们是否可以在不使用多个线程的情况下真正启动多个请求?

是的,这是一个真实世界的例子(伪asp.net-mvc和实体框架,例如,EF将对Sql Server进行IO调用)。

public async ActionResult()
{
  var model = new Company();

  using (var db1 = new DbContext)
  using (var db2 = new DbContext)
  {
    var task1 = db1.Employees.ToListAsync();
    var task2 = db1.Managers.ToListAsync();

    await Task.WhenAll(task1, task2);

    model.employees = task1.Result;
    model.managers = task2.Result;
  }

  return View(model);
}