异步编程
我第一次听到异步是在做前端开发的时候,用 js 发一个 http ajax 请求就是一个异步操作。
"异步"经常和"回调","多线程"一起出现
关于它们之间的爱恨情仇可以参考下面 :
http://kb.cnblogs.com/page/116095/
http://www.cnblogs.com/jesse2013/p/async-and-await.html
http://www.cnblogs.com/jesse2013/p/asynchronous-programming-in-dotnet.html
http://blog.zhaojie.me/2008/02/use-async-operation-properly.html
http://channel9.msdn.com/Events/TechEd/NorthAmerica/2013/DEV-B337#fbid=
最后一篇是英文视频,是比较新的.
.net中的异步在从前是比较难编写的,一直到4.5发布后 async & await 的写法看上去才比较舒服些。
我这里只说一些基本的概念,说的不对还请高手纠正,感谢
异步常用的有2种,
第一种是在做 I/O 和远程调用的时候, 挂起当前线程,让线程回到线程池去处理其它请求,一直到I/O完毕再回来这个请求处理后续的事儿。
要实现这个是需要硬件和操作系统配合的,借助硬件的DMA功能(直接内存访问)实现的.
做远程调用的时候其实是网卡和内存在工作,CPU在发起一次命令后就休息了,然后等到它们结束时会发出一个中断给CPU,这时CPU才执行回调处理。
这个部分我们基本上只能调用微软写好的API接口去做这些事。
第二种是在处理耗时较长的计算时,开多几个线程去分工处理它,这好比F1赛事换轮胎的场景。
这也是需要硬件配合,要有多核CPU才行.
第一种是我们最常见到的,这种异步是不需要开多线程去完成的。
第二种则需要开多线程去完成,一个例子就是写 winform 时,ui主线程是不能阻塞的,因为要处理页面嘛,那么如果有复杂的计算就可以开子线程去处理,子线程处理完了再通知主线程.
这2种对性能都是好的,但是手法其实差很多
如果你想要做一些I/O或是远程的话,异步是好的。
如果你想做复杂的计算,多线程是好的。
委托的beginInvoke是多线程的概念
下面我来写一些经常用到的异步方法
WebForm
protected void Page_Load(object sender, EventArgs e) { try { //最好是使用 RegisterAsyncTask, 而不要在 async void Page_Load RegisterAsyncTask(new PageAsyncTask(async (t) => { //token具体用法以后才研究,先记入起来 var source = CancellationTokenSource.CreateLinkedTokenSource( Response.ClientDisconnectedToken, Request.TimedOutToken, t); var token = source.Token; using (DB db = new DB()) { var data = await db.products.ToListAsync(token); } })); } catch (Exception ex) { throw; } }
<%@ Page Language="C#" AutoEventWireup="true" Async="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
要加上 Async="true"
Ashx
public class Handler : HttpTaskAsyncHandler { public override async Task ProcessRequestAsync(HttpContext context) { var json = abc(); var json2 = abc(); await Task.WhenAll(json, json2); await json; context.Response.ContentType = "text/plain"; context.Response.Write(json.Result); } public async Task<string> abc() { string json = ""; using (DB db = new DB()) { var data = await db.products.ToListAsync(); json = JsonConvert.SerializeObject(data); } return json; } public override bool IsReusable { get { return false; } } }
这里继承了 HttpTaskAsyncHandler ,通过 override 来实现的.
Web API
http://www.codeproject.com/Tips/805923/Asynchronous-programming-in-Web-API-ASP-NET-MVC
最后给一些忠告 :
1.Task.Run,Task.ContinueWith,不要随便用, 它们都会使用更多的线程,除非你的目的是F1赛车的情况.
2.不要用 Task.Wait | Task.Result . 用 Task.WhenAll & await
3.用 HttpTaskAsyncHandler , 不要用 IHttpAsyncHandler. 因为后者复杂,当然如果你很牛就没事儿。
更新 2015-09-22
之前没有实现在 HttpModule 时如果也要异步的话
参考 : http://brockallen.com/2013/07/27/implementing-async-http-modules-in-asp-net-using-tpls-task-api/
public class AuthenAndAutho : IHttpModule { public void Init(HttpApplication app) { var wrapper = new EventHandlerTaskAsyncHelper(DoAsyncWork); app.AddOnBeginRequestAsync(wrapper.BeginEventHandler, wrapper.EndEventHandler); //有各种的 AddOn } async Task DoAsyncWork(object sender, EventArgs e) { var app = (HttpApplication)sender; var ctx = app.Context; var client = new HttpClient(); var result = await client.GetStringAsync("http://foo.com"); } public void Dispose() { } }
更新 : 2015-12-08
如果要在 async 下做 Response.Redirect("path",false); 第2个参数要是 false 哦.