谈谈异步编程及在ASP.NE Core MVC中的使用

异步编程(Task)基本理解

Task类是.NET 4.0之后提供的异步操作抽象,需要导入System.Threading.Tasks命名空间。

Task类用于表示无返回值的异步操作,对于带有返回值的异步操作应使用Task类的子类Task<TResult>。

Task类和Task<TResult>类,后者是前者的泛型版本。TResult类型为Task所调用方法的返回值。

主要区别在于Task构造函数接受的参数是Action委托,而Task<TResult>接受的是Func<TResult>委托

  • Task(Action) 
  • Task<TResult>(Func<TResult>)  

Task 异步编程的通俗理解

   Task 异步编程模式是潮流,当然就是因为执行效率高。怎么理解异步编程,通俗讲就是“未来完成时”。Task的表示他现在不一定有结果,等有结果了,他会通知你。当然实际上的意义就是,CPU现在可以忙别的,等有结果了再去处理你的。想想医院的医生看病就OK,他让你先做检查,先去化验,等你拿着化验结果到了,他再具体判定。在你去化验的同时医生也不会闲着,他用这段时间给后面病人诊断。理解了这个,技术上就能搞清楚了。简言之,就是“不空等结果,保存环境,等有结果了,恢复环境继续运行。同时他在等结果的同时去执行其他任务”。

  异步就是不阻塞,不等 Task 方法执行完而是先去执行这个方法后边的代码。当写了 await 关键字的时候,就可以让 Task 执行完毕了才去执行它后边的代码。

Task类中的一些常用方法及应用

// 将参数中的异步操作在当前调度器中排队,并返回Task对象

(1)

public static Task Run(Action action);

(2)

public static Task<TResult> Run<TResult>(Func<TResult> function);

Task.Run方法是Task类中的静态方法,接受的参数是委托。返回值是为该Task对象。

Task.Run(Action)

Task.Run<TResult>(Func<Task<TResult>>)

(3)

public void Wait();  //等待当前Task任务完成

 

Task类创建的任务会加入线程池中。在实际开发中,更多情况下使用Task类的静态方法Run()或者工厂类TaskFactory的成员方法StartNew()来创建和启动新的任务(TaskFactory taskFactory = new TaskFactory();taskFactory.StartNew(Action);)

虽然在异步方法中提示返回值可以为Task、Task<T>或者void,但是建议返回值选择Task或者Task<T>

例子1:创建控制台项目(.Net Core的)

static void Main(string[] args) 

        { 

            Task Task1 = new Task(() => Console.WriteLine("Task1")); 

            Task1.Start(); 

            Console.ReadKey(); 

        } 

通过实例化一个Task对象,然后Start,这种方式中规中矩,但是实际应用中,通常采用更方便快捷的方式。

Task.Run(() => Console.WriteLine("异步编程"));这种方式直接运行了Task,不像上面的方法还需要调用Start();

默认情况下,Task任务是由线程池线程异步执行。要知道Task任务的是否完成,可以通过task.IsCompleted属性获得,也可以使用task.Wait来等待Task完成。Wait会阻塞当前线程。

例子2:

static void Main(string[] args)
        {
            Task Task1 = Task.Run(() =>
            {
                Thread.Sleep(5000);
                Console.WriteLine("Foo");
                Thread.Sleep(5000);
            });
            Task1.Wait();//阻塞当前线程 ,等待上面任务完成再执行下面的代码
            Console.WriteLine(Task1.IsCompleted);
            
            Console.WriteLine(Task1.IsCompleted);
            Console.WriteLine("ok");
            Console.ReadKey();
        }

运行结果:

 

对比一下:

static void Main(string[] args)

        {

            Task Task1 = Task.Run(() =>

            {

                Thread.Sleep(5000);

                Console.WriteLine("Foo");

                Thread.Sleep(5000);

            });

            Console.WriteLine(Task1.IsCompleted);

            Task1.Wait();//阻塞当前线程,等待上面任务完成再执行下面的代码 

            Console.WriteLine(Task1.IsCompleted);

            Console.WriteLine("ok");

            Console.ReadKey();

        }

运行结果:

 

async/await 关键字

C# 5.0之后引入了async和await关键字,更好的支持并发操作。

async用于标记异步方法。async标记的方法返回值必须为Task、Task<TResult>、void其中之一。

await用于等待异步方法的结果。await关键字可以用在async方法和Task、Task<TResult>之前,用于等待异步任务执行结束。

如:await _resultRepository.ListAsync();

ASP.NET CORE MVC实例

下面采用一段MVC设计代码来说明一下Task类在MVC Designer中的如何使用

看下面这段代码,这里先定义一个接口,该接口定义异步操作

public interface IAlbumService
    {
       //返回一个List<Album>的泛型列表
        Task<List<Album>> GetAllAsync();
      //返回一个Album model
        Task<Album> GetByIdAsync(int id);
      //返回一个Album model
        Task<Album> AddAsync(Album model);
      //无返回值的异步操作
        Task UpdateAsync(Album model);
     //无返回值的异步操作
        Task DeleteAsync(Album model);
    }

然后实现该接口:实现该接口中Task类

public class AlbumEfService : IAlbumService
    {
        //声明一个只读字段,这里HeavyContext是一个数据库Model
        private readonly HeavyContext _context;

        //依赖注入该model
        public AlbumEfService(HeavyContext context)
        {
            _context = context;
        }

        public async Task<List<Album>> GetAllAsync()
        {
            return await _context.Albums.ToListAsync();
        }

        public Task<Album> GetByIdAsync(int id)
        {
            return _context.Albums.FindAsync(id);
        }

        public async Task<Album> AddAsync(Album model)
        {
            _context.Albums.Add(model);
            await _context.SaveChangesAsync();
            return model;
        }

        public async Task UpdateAsync(Album model)
        {
            _context.Entry(model).State = EntityState.Modified;
            await _context.SaveChangesAsync();
        }

        public async Task DeleteAsync(Album model)
        {
            _context.Albums.Remove(model);
            await _context.SaveChangesAsync();
        }
    }

在Controller中注入该接口服务

[Authorize]
    public class AlbumController : Controller
    {
        private readonly IAlbumService _albumService;

        public AlbumController(IAlbumService albumService)
        {
            _albumService = albumService;
        }

        // GET: Album
        public async Task<ActionResult> Index()
        {
            var albums = await _albumService.GetAllAsync();
            return View(albums);
        }

        // GET: Album/Details/5
        public async Task<ActionResult> Details(int id)
        {
            var album = await _albumService.GetByIdAsync(id);
            if (album == null)
            {
                return RedirectToAction(nameof(Index));
            }
            return View(album);
        }

        // GET: Album/Create
        public ActionResult Create()
        {
            var newModel = new AlbumCreateViewModel();
            return View(newModel);
        }
        ......

在Startup中注入操作Album model所需要的服务

  services.AddScoped<IAlbumService, AlbumEfService>();

提问:服务注入的方式还有哪两种:

(1)最常用的注入方式,以接口形式暴露服务

services.AddScoped( typeof(IUserService), typeof(UserService));

services.AddScoped<IUserService, UserService>();

(2)自己注入自己,以实现形式暴露服务

services.AddScoped< UserService>();

services.AddScoped( typeof( UserService));

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值