网站首页 > 知识剖析 正文
背景
已经有很多文章记录了Web程序中采用异步编程的优势和.Net异步编程的用法, 异步编程虽然不能解决查询数据库的瓶颈, 但是利用线程切换,能最大限度的弹性利用工作线程, 提高了web服务的响应能力。
9012年了,再不会异步编程你是真老了
本文要说的是利用异步编程中的取消机制缓解数据库的查询瓶颈,开发者只需在MVC/WebAPI查询方法体内关注CancellationToken并适时取消异步任务, 这将大大提高应用的响应能力。
头脑风暴
想象你请求某网站页面,该页面正闪着菊花试图努力绽放(正在加载),最终你忍不了:
① F5刷新
② 转向其他页面
③ 点击浏览器“停止”按钮
对于Web服务器,用户快速刷新5次,服务器将被迫接受 5倍的工作量,这是因为即使用户刷新了浏览器(或点击停止按钮), 虽然取消了原始浏览器请求,但是Web服务器并不Care,仍然按部就班处理进入HTTP pipeline的请求(MVC/WebAPI 中默认行为,②③场景类似)
在异步编程中能向任务发出Cancellation信号,停止web服务器后端查询行为。在.NET中,这是使用CancellationToken完成的:
取消令牌的实例传递到异步任务
异步任务监视令牌,以查看请求是否已经被取消。
如果请求取消,则应停止执行正在执行的操作。.NET中的大多数异步方法将具有接受取消令牌的重载。
tip
本文取消的请求,指的是耗时长的服务端读取请求(返回数据但不修改数据的查询),取消已修改数据的请求对于用程序可能不是一个好的选择:
① 是否真的要因为用户导航到应用的另一个页面而取消保存?也许可以,但也可能不会。
② 提高了复杂性,因为数据库服务器可能需要回滚事务,这是一项昂贵的操作。
AspNetCore实践
访问MyReallySlowReport页面,等待5s,最终他们放弃去了其他页面:
所有正在进行的请求都将被取消。
P1 监测CancellationToken令牌
MVC/WebAPI能收到取消请求的信号。开发者只需要在Controller Action中添加CancellationToken参数,并在后续行为中监测该取消信号。
public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
List<ReportItem> items;
using (ApplicationDbContext context = new ApplicationDbContext)
{
items = await context.ReportItems.ToListAsync(cancellationToken);
}
return View(items);
}
上述EF的调用api支持取消异步操作,故很容易取消SQL的查询行为;对于自定义的长耗时查询行为,可以使用CancellationToken的原生触发用法:
public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)
{
List<ReportItem> items;
using (ApplicationDbContext context = new ApplicationDbContext)
{
items = await context.ReportItems.ToListAsync(cancellationToken);
}
foreach (var item in items)
{
cancellationToken.ThrowIfCancellationRequested;
// slow non-cancellable work
Thread.Sleep(1000);
}
return View(items);
}
P2处理取消异步操作向上抛出的异常处
Web服务器触发取消信号,一般会向上会抛出OperationCanceledException或TaskCancellationException,所以为了记录这种非常规异常,建议采用独立的ExceptionFilter。
public class OperationCancelledExceptionFilter : ExceptionFilterAttribute
{
private readonly ILogger _logger;
public OperationCancelledExceptionFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<OperationCancelledExceptionFilter>;
}
public override void OnException(ExceptionContext context)
{
if(context.Exception is OperationCanceledException)
{
_logger.LogInformation("Request was cancelled");
context.ExceptionHandled = true;
context.Result = new StatusCodeResult(400);
}
}
}
P3 想要得到CTO的大拇指,继续思考吧
以上是后端程序员利用取消机制缓解异步查询瓶颈的操作,从web应用全流程角度思考,这个优化还能提升吗?
> 以上是传统的网页请求场景,在取消请求时,浏览器帮助我们发起了Cancellation信号。
> 想想日益常见的SPA程序(单页面程序),绝大部分页面请求都是Ajax请求,你点击应用的另外一个“页面”(JS代码维护页面导航),浏览器不会自动取消请求。所以在SPA应用中要前端自己发出取消请求的信号:
var xhr = $.get("/api/myslowreport", function(data){
//show the data
});
//If the user navigates away from this page
xhr.abort
前后端程序猿通力配合,应用的吞吐量和响应能力极大提升,CTO要给各位加薪了。
猜你喜欢
- 2024-11-17 Skywalking-03:Skywalking本地调试
- 2024-11-17 一个基于Asp.Net Core + Angular + Bootstrap开源CMS系统
- 2024-11-17 AspNet在windowserver中如何让IIS支持高并发
- 2024-11-17 在ASP.NET Core web API中使用Swagger/OpenAPI(Swashbuckle)
- 2024-11-17 Dev ASP.NET界面开发2020:全新升级图表控件
- 2024-11-17 Web前端培训:五种JavaScript富文本编辑器的比较
- 2024-11-17 aspnet数据库连接mssql配置(基础入门6)
- 2024-11-17 aspnet向数据库插入数据(基础入门5)
- 2024-11-17 Mvc-AspNet Mvc选择题(50题)(asp.net mvc运行原理)
- 2024-11-17 aspnet查询数据库的数据(基础入门3)
- 04-29php开发者composer使用看这一篇就够了
- 04-29引用和变量声明在不同语言中的实作
- 04-29PHP 没你想的那么差
- 04-29Ubuntu linux 上的 Nginx 和 Php 安装
- 04-29CentOS下通过yum搭建lnmp(单版本PHP)
- 04-29为什么 PHP8 是个高性能版本
- 04-29PHP8函数包含文件-PHP8知识详解
- 04-29使用无参数函数进行命令执行
- 最近发表
- 标签列表
-
- xml (46)
- css animation (57)
- array_slice (60)
- htmlspecialchars (54)
- position: absolute (54)
- datediff函数 (47)
- array_pop (49)
- jsmap (52)
- toggleclass (43)
- console.time (63)
- .sql (41)
- ahref (40)
- js json.parse (59)
- html复选框 (60)
- css 透明 (44)
- css 颜色 (47)
- php replace (41)
- css nth-child (48)
- min-height (40)
- xml schema (44)
- css 最后一个元素 (46)
- location.origin (44)
- table border (49)
- html tr (40)
- video controls (49)