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   這里介紹了異步的詳細發展史。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM