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 "":
student = new Student() { StuNo = "", Name = "张三", Sex = "男", Age = };
break;
case "":
student = new Student() { StuNo = "", Name = "钱七七", Sex = "女", Age = };
break;
case "":
student = new Student() { StuNo = "", Name = "李四", Sex = "男", Age = };
break;
default:
student = new Student() { StuNo = "", Name = "王五", Sex = "男", Age = };
break;
} return student;
} /// <summary>
/// 根据学号获取学生信息(异步)
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
public virtual async Task<Student> GetStuInfoAsync(string stuNo)
{
return await Task.Run(() => this.GetStuInfo(stuNo));
}
}
}

然后是服务层接口:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Service
{
/// <summary>
/// 学生类服务层接口
/// </summary>
public interface IStudentService
{
/// <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;
using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.Service.Impl
{
/// <summary>
/// 学生类服务层
/// </summary>
public class StudentService : IStudentService
{
/// <summary>
/// 定义仓储层学生抽象类对象
/// </summary>
protected IStudentRepository StuRepository; /// <summary>
/// 空构造函数
/// </summary>
public StudentService() { } /// <summary>
/// 构造函数
/// </summary>
/// <param name="stuRepository">仓储层学生抽象类对象</param>
public StudentService(IStudentRepository stuRepository)
{
this.StuRepository = stuRepository;
} /// <summary>
/// 根据学号获取学生信息
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
public Student GetStuInfo(string stuNo)
{
var stu = StuRepository.GetStuInfo(stuNo);
return stu;
} /// <summary>
/// 根据学号获取学生信息(异步)
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
public virtual async Task<Student> GetStuInfoAsync(string stuNo)
{
return await StuRepository.GetStuInfoAsync(stuNo);
}
}
}

最后进行控制器中的调用:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using TianYa.DotNetShare.CoreAutofacDemo.Models; using TianYa.DotNetShare.Service;
using TianYa.DotNetShare.Repository;
using TianYa.DotNetShare.Repository.Impl; namespace TianYa.DotNetShare.CoreAutofacDemo.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 定义仓储层学生抽象类对象
/// </summary>
private IStudentRepository _stuRepository; /// <summary>
/// 定义服务层学生抽象类对象
/// </summary>
private IStudentService _stuService; /// <summary>
/// 定义服务层学生抽象类对象
/// 属性注入:访问修饰符必须为public,否则会注入失败。
/// </summary>
public IStudentService StuService { get; set; } /// <summary>
/// 定义仓储层学生实现类对象
/// 属性注入:访问修饰符必须为public,否则会注入失败。
/// </summary>
public StudentRepository StuRepository { get; set; } /// <summary>
/// 通过构造函数进行注入
/// 注意:参数是抽象类,而非实现类,因为已经在Startup.cs中将实现类映射给了抽象类
/// </summary>
/// <param name="stuRepository">仓储层学生抽象类对象</param>
/// <param name="stuService">服务层学生抽象类对象</param>
public HomeController(IStudentRepository stuRepository, IStudentService stuService)
{
this._stuRepository = stuRepository;
this._stuService = stuService;
} public IActionResult Index()
{
var stu1 = StuRepository.GetStuInfo("");
var stu2 = StuService.GetStuInfo("");
var stu3 = _stuService.GetStuInfo("");
var stu4 = _stuRepository.GetStuInfo("");
string msg = $"学号:10000,姓名:{stu1.Name},性别:{stu1.Sex},年龄:{stu1.Age}<br />";
msg += $"学号:10001,姓名:{stu2.Name},性别:{stu2.Sex},年龄:{stu2.Age}<br/>";
msg += $"学号:10002,姓名:{stu3.Name},性别:{stu3.Sex},年龄:{stu3.Age}<br/>";
msg += $"学号:10003,姓名:{stu4.Name},性别:{stu4.Sex},年龄:{stu4.Age}<br/>"; return Content(msg, "text/html", System.Text.Encoding.UTF8);
} public async Task<IActionResult> Privacy()
{
var stu = await _stuService.GetStuInfoAsync("");
return Json(stu);
} [ResponseCache(Duration = , Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

至此完成处理,我们来访问一下/home/privacy,看看是否正常

可以看出是正常的

下面我们演示一下什么时候需要用到result属性:

//用了await则不需要Result属性
public async Task<IActionResult> Privacy()
{
var stu = await _stuService.GetStuInfoAsync("");
return Json(stu);
}
//没有用await则需要Result属性
public async Task<IActionResult> Privacy()
{
var stu = _stuService.GetStuInfoAsync("").Result;
return Json(stu);
}

至此我们的异步编程就讲解完了。

总结:

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

2、如果用了await则方法必须使用async来修饰,并且是Task的类型。

demo源码:

链接:https://pan.baidu.com/s/1Wb0Mebm-nh9YFOaYNLwO-g
提取码:1ayv

参考博文:https://www.cnblogs.com/fei686868/p/9637310.html

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

ASP.NET Core Web 应用程序系列(四)- ASP.NET Core 异步编程之async await的更多相关文章

  1. ASP.NET 异步编程之Async await

    本文重点介绍的是.NET Framework4.5 推出的异步编程方案  async await 请先看个5分钟的微软演示的视频:视频地址: https://channel9.msdn.com/Blo ...

  2. ASP.NET Core Web 应用程序系列(五)- 在ASP.NET Core中使用AutoMapper进行实体映射

    本章主要简单介绍下在ASP.NET Core中如何使用AutoMapper进行实体映射.在正式进入主题之前我们来看下几个概念: 1.数据库持久化对象PO(Persistent Object):顾名思义 ...

  3. ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)

    在正式进入主题之前我们来看下几个概念: 一.依赖倒置 依赖倒置是编程五大原则之一,即: 1.上层模块不应该依赖于下层模块,它们共同依赖于一个抽象. 2.抽象不能依赖于具体,具体依赖于抽象. 其中上层就 ...

  4. ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)

    在上一章中主要和大家分享了在ASP.NET Core中如何使用Autofac替换自带DI进行构造函数的批量依赖注入,本章将和大家继续分享如何使之能够同时支持属性的批量依赖注入. 约定: 1.仓储层接口 ...

  5. ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)

    在上一章中主要和大家分享在MVC当中如何使用ASP.NET Core内置的DI进行批量依赖注入,本章将继续和大家分享在ASP.NET Core中如何使用Autofac替换自带DI进行批量依赖注入. P ...

  6. 【目录】循序渐进学.Net Core Web Api开发系列

    当前标签: 循序渐进学.Net Core Web Api开发系列   循序渐进学.Net Core Web Api开发系列[16]:应用安全续-加密与解密 NET未来之路 2019-03-13 15: ...

  7. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  8. Asp.Net Core Web应用程序—探索

    前言 作为一个Windows系统下的开发者,我对于Core的使用机会几乎为0,但是考虑到微软的战略规划,我觉得,Core还是有先了解起来的必要. 因为,目前微软已经搞出了两个框架了,一个是Net标准( ...

  9. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    C#中的函数式编程:递归与纯函数(二)   在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...

随机推荐

  1. ubuntu14.04编译vim8.1

    安装依赖 这一步其实我没做,直接下载编译成功了.估计有些包不是必需的.姑且列在这里供参考 sudo apt install libncurses5-dev libgnome2-dev libgnome ...

  2. FCC---CSS Flexbox: Align Elements Using the justify-content Property

    Sometimes the flex items within a flex container do not fill all the space in the container. It is c ...

  3. iOS核心动画高级技巧-4

    8. 显式动画 显式动画 如果想让事情变得顺利,只有靠自己 -- 夏尔·纪尧姆 上一章介绍了隐式动画的概念.隐式动画是在iOS平台创建动态用户界面的一种直接方式,也是UIKit动画机制的基础,不过它并 ...

  4. 安卓JNI精细化讲解,让你彻底了解JNI(二):用法解析

    目录 用法解析 ├── 1.JNI函数 │ ├── 1.1.extern "C" │ ├── 1.2.JNIEXPORT.JNICALL │ ├── 1.3.函数名 │ ├── 1 ...

  5. MySQL数据库Group by分组之后再统计数目Count(*)与不分组直接统计数目的区别

    简述问题“统计最新时刻处于某一状态的设备的数量” 1. 首先子查询结果,可以看到每个设备最新的状态信息 2.1 在子查询的基础上,对设备状态进行分组,进行统计每个状态的设备数量 2.1.1 可以看到处 ...

  6. 精通awk系列(1):安装新版本的gawk

    回到: Linux系列文章 Shell系列文章 Awk系列文章 安装新版本gawk awk有很多种版本,例如nawk.gawk.gawk是GNU awk,它的功能很丰富. 本教程采用的是gawk 4. ...

  7. idea个性化配置

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  8. ES中index和type区分

    参考: https://bayescafe.com/database/elasticsearch-using-index-or-type.html https://www.cnblogs.com/hu ...

  9. 【Puppeteer】puppeteer安装/常用的方法以及一个小栗子(Youtube油管自动评论)

    这里介绍的是Win平台的安装方法,其他平台请至Github>Puppeteer. 首先要安装node.js 可以看我这篇的开头>[Angular]学习笔记-环境部署.项目建立相关 1.新建 ...

  10. web项目踩坑过程

    sql函数设计: 一开始本来是直接用Java的jdbc直接传输操作语句的.但后来学了存储过程发现存储过程可以提高不少的效率.就重构了自己对数据库的操作代码.包括:开启,查找,修改,关闭. 开启:直接使 ...