WebApi异步操作,我是否必须通过所有调用链创建异步方法?

时间:2018-01-24 15:27:40

标签: c# asp.net asynchronous async-await

我正在尝试使我的WebApi异步,以便在访问数据库时不阻止处理请求的ASP.net线程。所以我创建了以下代码。根据我的理解,当调用此操作时,会创建远离ASP.net线程池的新线程来处理GetBalance方法,并且过去处理此操作请求的线程将被释放并返回池中,直到在GetBalance方法完成其IO之前由其他请求使用。这是对的吗?

我读过的一篇文章建议我的异步调用必须一直遍历所有调用链,直到达到最低级别的异步调用,在本例中为实体框架异步调用。另外,下面的代码创建的新线程仍将在ASP.net线程池中创建,我将释放一个线程来占用另一个线程,这会破坏异步等待中所做的全部工作,以提高此WebApi的可伸缩性。

有人可以解释一下这是如何工作的吗?如果我的理解是正确的?

    public async Task<Account> Balance(int number)
    {
        Task<Account> task = GetBalanceAsync(number);
        await task;

        return task.Result;
    }

    Task<Account> GetBalanceAsync(int number)
    {
        return Task.Factory.StartNew(() => GetBalance(number));
    }

    Account GetBalance(int number)
    {
        using (AccountServices accountService = new AccountServices())
        {
            Account account = accountService.Find(number);

            return account;
        }
    }

1 个答案:

答案 0 :(得分:4)

只有一个线程池。 ASP.NET请求只在常规线程池线程上运行。

  

据我所知,当调用此操作时,会创建远离ASP.net线程池的新线程来处理GetBalance方法,并且过去处理此操作请求的线程将被释放并返回池中,直到其他请求使用,直到GetBalance方法完成其IO。这是对的吗?

是;您的代码从线程池(StartNew)获取一个线程,然后将一个线程返回到线程池(await)。

  

我读过的一篇文章建议我的异步调用必须一直遍历所有调用链,直到达到最低级别的异步调用,在本例中为实体框架异步调用。另外,下面的代码创建的新线程仍将在ASP.net线程池中创建,我将释放一个线程来占用另一个线程,这会破坏异步等待中所做的全部工作,以提高此WebApi的可伸缩性。

Yes, that's exactly correct。发布的代码增加了复杂性和开销,并且性能将比同步代码更差:

public Account Balance(int number)
{
  return GetBalance(number);
}

Account GetBalance(int number)
{
  using (AccountServices accountService = new AccountServices())
  {
    return accountService.Find(number);
  }
}

完全异步的解决方案将具有更好的可扩展性:

public async Task<Account> Balance(int number)
{
  return await GetBalanceAsync(number);
}

Task<Account> GetBalanceAsync(int number)
{
  using (AccountServices accountService = new AccountServices())
  {
    return await accountService.FindAsync(number);
  }
}