写点什么

异步编程的取消机制 竟然还有这样的效果, 要不要了解一下?

  • 2021 年 11 月 12 日
  • 本文字数:1521 字

    阅读完需:约 5 分钟

  • 异步任务监视令牌,以查看请求是否已经被取消。

  • 如果请求取消,则应停止执行正在执行的操作。.NET 中的大多数异步方法将具有接受取消令牌的重载。


本文所说的请求是,耗时长的服务端读取查询(返回数据但不修改数据的查询)。取消已修改数据的请求对于用程序可能不是一个好的选择:



? ? -? 是否真的要因用户导航到应用程序中的另一个页面而取消保存?也许可以,但也可能不会。



? ?-? 除了数据问题,这也不会提高性能,因为数据库服务器将需要回滚该事务,这可能是一项昂贵的操作。


ASP.NET Core 实践



监测 CancellationToken 令牌

访问?MyReallySlowReport 页面,等待 5s,最终他们放弃了,去了其他页面:



所有正在进行的请求都将被取消。


MVC/WebAPI 能接受到取消请求的信号。开发者只需要在 Controller Action 中添加 CancellationToken 参数,并在后续行为中监测该取消信号。


浏览器取消请求时,ASP.NET Core 根据CancellationTokenModelBinder自动将 HttpContext.RequestAborted 这个 token 绑定到 Action 的 CancellationToken 参数,CancellationTokenModelBinder 将会在调用 AddMvc()或 services.AddMvcCore()时被注入。?


public async Task<ActionResult> MyReallySlowReport(CancellationToken cancellationToken)


{


List<ReportItem> items;


using (ApplicationDbContext context = new ApplicationDbContext())


{


items = await context.ReportItems.ToListAsync(cancellationToken);


}


return View(items);


}


以上代码显示: 很容易取消框架内置 API 的异步方法 (上面以 SQL 查询行为为例),因为上述 EF 的调用 api 支持取消异步操作;


对于自定义的长耗时查询行为,可以使用 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);


}


从以上代码也可推断出: CancellationToken 适用于同步方法。

处理取消操作抛出的异常?

【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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);


}


}


}


SPA 应用




以上是后端程序员利用 取消机制 缓解后台性能压力,针对的是浏览器触发的取消操作。 从 web 请求的产生来源分析,除了浏览器能发起请求, 编程也可以发起请求


? 想想日益常见的 SPA 程序(单页面程序),绝大部分页面请求都是 ajax 请求,你点击应用的另外一个“页面(JS 代码维护页面导航),浏览器不会自动取消请求。


在 SPA 应用中,前端发起的 ajax 请求, 若要取消,是需要以编程方式来完成的。


所以我墙裂建议,在 2C 的 SPA 应用中,切换“页面“”时请终止原页面的所有 ajax 请求。

评论

发布
暂无评论
异步编程的取消机制 竟然还有这样的效果, 要不要了解一下?