PS:异步编程的本质就是新开任务线程来处理。
约定:异步的方法名均以Async结尾。
实际上呢,异步编程就是通过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<TResult>,catch到的异常会包装在属性里面,调用方法就可以从中获取异常信息,并选择正确的处理方式。
2、Task
你如果只是想知道执行的状态,而不需要一个具体的返回结果时,请使用Task。
与void对比呢,Task可以使用await进行等待新线程执行完毕。而void不需要等待。
3、Task<TResult>
当你添加async关键字后,需要返回一个将用于后续操作的对象,请使用Task<TResult>。
主要有两种方式获取结果值,一个是使用Result属性,一个是使用await。他们的区别在于:如果你使用的是Result,它带有阻塞性,即在任务完成之前进行访问读取它,当前处于活动状态的线程都会出现阻塞的情形,一直到结果值可用。所以,在绝大多数情况下,除非你有绝对的理由告诉自己,否则都应该使用await,而不是属性Result来读取结果值。
接下来我们来看个例子,在上一章的基础上我们添加异步的方法。
首先是仓储层接口:
using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository { /// <summary> /// 学生类仓储层接口 /// </summary> public interface IStudentRepository { /// <summary> /// 根据学号获取学生信息 /// </summary> /// <param name="stuNo">学号</param> /// <returns>学生信息</returns> Student GetStuInfo(string stuNo); /// <summary> /// 根据学号获取学生信息(异步) /// </summary> /// <param name="stuNo">学号</param> /// <returns>学生信息</returns> Task<Student> GetStuInfoAsync(string stuNo); } }
接着是仓储层实现:
using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository.Impl { /// <summary> /// 学生类仓储层 /// </summary> public class StudentRepository : IStudentRepository { /// <summary> /// 根据学号获取学生信息 /// </summary> /// <param name="stuNo">学号</param> /// <returns>学生信息</returns> public Student GetStuInfo(string stuNo) { //数据访问逻辑,此处为了演示就简单些 var student = new Student(); switch (stuNo) { case "10000": student = new Student() { StuNo = "10000", Name = "张三", Sex = "男", Age = 20 }; break; case "10001": student = new Student() { StuNo = "10001", Name = "钱七七", Sex = "女", Age = 18 }; break; case "10002": student = new Student() { StuNo = "10002", Name = "李四", Sex = "男", Age = 21 }; break; default: student = new Student() { StuNo = "10003", Name = "王五", Sex = "男", Age = 25 }; break; } return student; } /// <summary> /// 根据学号获取学生信息(异步) /// </summary> /// <param name="stuNo">学号</param> /// <returns>学生信息</returns> public virtual async Task<Student> GetStuInfoAsy