异步编程

我第一次听到异步是在做前端开发的时候,用 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 哦. 

 

posted @ 2015-04-02 00:06  兴杰  阅读(286)  评论(0编辑  收藏  举报