我正在尝试使我的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;
}
}
答案 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);
}
}