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,看看是否正常

可以看出是正常的

下面我们演示一下什么时候需要用到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

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