在工作中,我们正在讨论是否应在具有20个用户的同步快速查询(例如EF的dbContext.Table.First()
)而不是异步版本的ASP.NET Core应用程序中使用,因为要花更多时间为异步创建另一个线程操作。
我对这两个版本进行了基准测试。
该应用程序在Windows 10计算机(i5、16 Gb,当前计时器间隔:0.999毫秒)上运行。该数据库位于本地网络中Docker中的另一台计算机上。
public async Task<DailyExchangeRate> GetExchangeRateAsync(int currencyId, DateTime date)
{
return await dbContext.DailyExchangeRates
.Where(dr => dr.CurrencyId == currencyId)
.FirstOrDefaultAsync(dr => dr.Date == date.Date);
}
public DailyExchangeRate GetExchangeRate(int currencyId, DateTime date)
{
return dbContext.DailyExchangeRates
.Where(dr => dr.CurrencyId == currencyId)
.FirstOrDefault(dr => dr.Date == date.Date);
}
为什么异步版本更快?
答案 0 :(得分:4)
由于需要更多时间来为异步操作创建另一个线程,因此代替了异步版本
为什么您认为每个异步操作都必须创建一个新线程?
已经有一个与服务器关联的线程池,这就是所谓的“解除阻塞”,说一个给定的线程,并使用它来处理另一个请求,因为对数据库的调用是异步的-无需直到SQL查询完成并返回。
在与数据库的连接方面,有一个EF处理的数据库连接池,使用FirstOrDefaultAsync
也会提高性能,因为它可能使用相同的连接来处理很少的数据库调用,而不是使用一个连接并等待db的结果-在FirstOrDefault
同步调用中
答案 1 :(得分:4)
async-await
并不是要使每个操作都更快,而是要通过重用线程来提高系统的可用性。如果您有足够的可用线程,则阻塞将使切换速度更快。
您的测试存在缺陷,因为您将JIT编译包括在内(请参阅第一个和第二个请求与下面的请求相比花费的时间)。您需要热身执行并排除异常值。查看BenchmarkDotNet的操作方式。
尝试将线程池的大小设置为较小的数目,并同时调用方法以查看差异。