欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET Core Web 应用程序系列(四)- ASP.NET Core 异步编程之async await

程序员文章站 2022-06-13 17:18:24
本系列将和大家分享下ASP.NET Core Web 应用程序的一些基础知识,本章主要分享ASP.NET Core 异步编程之async await的应用。 ......

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> 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("10000");
            var stu2 = stuservice.getstuinfo("10001");
            var stu3 = _stuservice.getstuinfo("10002");
            var stu4 = _sturepository.getstuinfo("1003");
            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("10000");
            return json(stu);
        }

        [responsecache(duration = 0, location = responsecachelocation.none, nostore = true)]
        public iactionresult error()
        {
            return view(new errorviewmodel { requestid = activity.current?.id ?? httpcontext.traceidentifier });
        }
    }
}

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

ASP.NET Core Web 应用程序系列(四)- ASP.NET Core 异步编程之async await

可以看出是正常的

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

//用了await则不需要result属性
public async task<iactionresult> privacy()
{
    var stu = await _stuservice.getstuinfoasync("10000");
    return json(stu);
}
//没有用await则需要result属性
public async task<iactionresult> privacy()
{
    var stu = _stuservice.getstuinfoasync("10000").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

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