zoukankan      html  css  js  c++  java
  • ASP.NET 异步编程之Async await

    本文重点介绍的是.NET Framework4.5 推出的异步编程方案  async await

    请先看个5分钟的微软演示的视频:
    视频地址: https://channel9.msdn.com/Blogs/ASP-NET-Site-Videos/async-and-await

    网络上已经有很多文章介绍了这个技术点的应用方式,但是举的例子都是.NET 自带提供的系统异步方法

    所以有些同学就看不大懂,如果是非系统自带的,如何实现异步。

    实际上,有时候一点就能通,把异步的本质了解明白了,也就懂了。

    异步编程的本质就是  新开任务线程来处理

    这个如何理解呢,请看下文介绍异步编程发展史

    static void Main(){
    
        new Thread(Go).Start();  // .NET 1.0开始就有的
        Task.Factory.StartNew(Go); // .NET 4.0 引入了 TPL
        Task.Run(new Action(Go)); // .NET 4.5 新增了一个Run的方法
    }

    这里大家不难看出,.NET 4.5之后引入了 Task.Run方法,实际上呢,异步编程就是通过这个实现的。

    了解线程的人也知道,新开一个线程来处理事务,这个很常见,但是在以往,是没办法接收线程里面返回的值的。

    所以这时候就该 await 出场了

    await,从字面意思,不难理解,就是等待的意思。

    执行await的方法必须是async修饰的,并且是Task的类型。 异步执行后,返回的信息存储在result属性中。

    但并非主进程就会卡在await行的代码上,执行到await方法之后,主线程继续往下执行,无需等待新的线程执行完再继续。

    当需要用到新线程返回的result结果时,此时主进程才会等待新线程执行完并返回内容。

    也就会说,若无需用到新线程返回的结果,那么主进程不会等待。

    async 和await呢,返回类型就3种,void,Task,Task<TResult>

    1、void

    如果在触发后,你懒得管,请使用 void。

    void 返回类型主要用在事件处理程序中,一种称为“fire and forget”(触发并忘记)的活动的方法。除了它之外,我们都应该尽可能是用 Task,作为我们异步方法的返回值。

    返回 void,意味着不能 await 该异步方法,即可能出现线程阻塞,并且也无法获取 exception,抛出的异常,通常这些异常会导致我们的程序失败,如果你使用的是 Task 和 Task<Result>,catch 到的异常会包装在属性里面,调用方法就可以从中获取异常信息,并选择正确的处理方式。

    2、Task
    你如果只是想知道执行的状态,而不需要一个具体的返回结果时,请使用 Task
    与void对比呢,是Task可以使用await进行等待新线程执行完毕。而void不需要等待。

    3、Task<TResult> 
    当你添加 async 关键字后,需要返回一个将用于后续操作的对象,请使用 Task<TResult>。

    主要有两种方式获取结果值,一个是使用 Result 属性,一个是使用 await。他们的区别在于:如果你使用的是 Result,它带有阻塞性。即在任务完成之前进行访问读取它,当前处于活动状态的线程都会出现阻塞的情形,一直到结果值可用。所以,在绝大多数情况下,除非你有绝对的理由告诉自己,否则都应该使用 await,而不是属性 Result 来读取结果值。

    下面我们直接看一些代码就懂了:

            /// <summary>
            /// 添加多条
            /// </summary>
            /// <param name="list"></param>
            /// <returns></returns>
            public virtual bool Add(IEnumerable<T> list)
            {
                CreateDataBase();//创建数据库连接
                foreach (T t in list)
                {
                    this.Add(t);
                }
                return true;
            }
    
            public virtual async Task<bool> AddAsync(IEnumerable<T> list)
            {
                return await Task.Run(() => this.Add(list));
            }

    正常情况下,我们约定,异步的方法名均以Async结尾

    以下是服务层调用

    /// <summary>
            /// 日志的json格式字符串 包含 title,url,level,descript
            /// </summary>
            /// <param name="content"></param>
            /// <returns></returns>
            public async Task<bool> AddAsync(string content)
            {
                using (var mongoDbContext = new Log.DAL.DbContext())
                {
                    if (!string.IsNullOrWhiteSpace(content))
                    {
                        Log.Model.Record model = Newtonsoft.Json.JsonConvert.DeserializeObject<Log.Model.Record>(content);
                        model.AddTime = DateTime.Now;
                        var result = await mongoDbContext.Record.AddAsync(model);
                        return result;
                    }
                    else
                    {
                        return false;
                    }
                }
            }

    再接着,进行控制器中的调用

      public async Task<ActionResult> Add(string content)
            {
                var flag = await new Log.Service.RecordService().AddAsync(content); ;
                return View();
            }

    下面的代码呢,我们演示一下什么时候需要用到result属性

    //不需要,因为用了await  
    
    public async Task<ActionResult> Detail(int id)
            {
                var model = await new DbContext().Record.FirstOrDefaultAsync(m => m.ID == id);
                return View(model);
            }
    
      //需要
      public async Task<ActionResult> Detail(int id)
            {
                var model =  new DbContext().Record.FirstOrDefaultAsync(m => m.ID == id).Result;
                return View(model);
            }

    这样,我们异步编程就讲解完了。本文主要是讲解异步是实质,学习这个需要异步有一定的学习和了解。

    总结:

    • 当你添加 async 关键字后,需要返回一个将用于后续操作的对象,请使用 Task<TResult>;

    • 你如果只是想知道执行的状态,而不需要知道具体的返回结果时,请使用 Task;

    • 如果在触发后,你懒得管,请使用 void。

    • 请尽量优先使用 Task<TResult> 和 Task 作为异步方法的返回类型。

    • 用了await,方法必须使用async来修饰。

     参考文章:http://www.cnblogs.com/jesse2013/p/async-and-await.html   这里介绍了异步的详细发展史。

  • 相关阅读:
    vi 命令 使用方法
    再论C++之垃圾回收(GC)
    Iterative (non-recursive) Quick Sort
    DirectSound的应用
    JavaScript也能求爱哦
    lol匹配算法
    一年成为Emacs高手(像神一样使用编辑器)
    SSH深度历险(四) Maven初步学�
    char* 和char[]的差别
    数据仓库与数据挖掘的一些基本概念
  • 原文地址:https://www.cnblogs.com/fei686868/p/9637310.html
Copyright © 2011-2022 走看看