use*_*050 4 c# asynchronous actionmethod async-await asp.net-core
我有一个关于 ASP.Net Core 中控制器方法的新手问题。我有下面两种不同的实现,一种是同步的,另一种是异步的。
问题 - 我认为,我理解同步和异步之间的区别,但是当涉及到进入控制器方法时,如果另一个用户在其中并且仍在执行过程中,ASP.Net 是否会阻止所有用户进入同步方法跑过它吗?
如果是这样,如果我预计有数千个并发用户,那么这种同步方法会大大减慢我的应用程序的速度,对吧?
那么我应该在几乎所有地方都使用异步控制器调用吗?除非我特别想将另一个用户锁定在外面!
这里是异步的
[HttpPost]
public async Task<IActionResult> PostRecordAsync([FromBody] Record record)
{
record = await RecordsContext.PostRecordAsync(_context, record);
return Ok(record);
}
public static async Task<Record> PostRecordAsync(MpidDbContext context, Record record)
{
context.Records.Add(record);
await context.SaveChangesAsync();
return record;
}
Run Code Online (Sandbox Code Playgroud)
和非异步
[HttpPost]
public ActionResult PostRecord([FromBody] Record record)
{
record = RecordsContext.PostRecord(_context, record);
return Ok(record);
}
public static Record PostRecord(MpidDbContext context, Record record)
{
context.Records.Add(record);
context.SaveChanges();
return record;
}
Run Code Online (Sandbox Code Playgroud)
不,同步调用不会阻塞。对于 Web 应用程序,异步方法将释放 Web 服务器线程以响应更多请求,而先前的调用正在等待来自资源或计算密集型操作的响应。
举个简单的例子。假设我有一个运行 100 个线程的 Web 服务器。这意味着它可以处理 100 个并发请求。由于要交给数据库进行一些读取和更新,每个请求最多需要 5 秒才能完成。
通过同步调用,如果有 500 个活动用户访问我的 Web 服务器,前 100 个用户将占用连接线程,而其余用户则等待线程。当操作完成时,下一个等待的请求将获得一个线程。请求在等待线程处理时可能会超时。
对于异步调用,如果有 500 个活动用户访问我的 Web 服务器,前 100 个用户将占用一个连接,但当等待操作并在数据库上运行时,Web 服务器线程将再次可用,开始处理另一个请求。当操作完成时,可以请求可用的 Web 服务器线程来处理结果并最终传回响应。Web 服务器通过接受请求并启动它们而无需等待先前的请求完成,以更灵敏的方式有效地处理更多并发请求。
异步确实会产生很小的性能成本,因为它需要能够在另一个线程上恢复执行,或者等待同步上下文。对于需要几秒钟才能运行的操作来说,这是非常值得的,但对于预计总是快速完成的方法来说,这会为所有调用增加少量但不必要的性能成本。作为一般规则,我默认使用同步调用,然后在我知道将有超过半秒左右的处理时间的情况下引入异步。(重要的数据库调用,例如ToList
或复杂的查询、文件 I/O 等)
使用 ASP.Net Core 时,您还需要谨慎对待异步代码,因为它在没有同步上下文的情况下运行。在引用非线程安全代码(如 DbContext)时使用异步的代码可能会出现以下问题:发生多个异步调用而不依次等待每个异步调用。
IE
// Should be Ok...
var product = await context.Products.SingleAsync(x => x.ProductId == productId);
var customer = await context.Customers.SingleAsync(x => x.CustomerId == customerId);
var newOrder = new Order { Product = product, Customer = customer};
// Not Ok...
var productGet = context.Products.SingleAsync(x => x.ProductId == productId);
var customerGet = context.Customers.SingleAsync(x => x.CustomerId == customerId);
var newOrder = new Order { Product = await productGet, Customer = await customerGet};
Run Code Online (Sandbox Code Playgroud)
这不是最好的示例,但异步操作将在工作线程上执行,因此第二个示例将在不同线程上同时发生两个上下文操作。第一个示例将在单独的线程上运行每个操作,但第二个操作只有在第一个操作完成后才会运行。第二个将同时运行操作。除非您对相同表或相关表运行异步操作,否则它可能不会出现问题。我无法具体说明这样的代码的含义,但如果您在异步方法中遇到问题,则需要注意。
归档时间: |
|
查看次数: |
1413 次 |
最近记录: |