您的位置:首页 > 编程语言 > ASP

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

2020-03-11 13:17 591 查看

异步编程(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:

[code]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();
}

运行结果:

 

对比一下:

[code]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中的如何使用

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

[code]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类

[code]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中注入该接口服务

[code][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所需要的服务

[code]  services.AddScoped<IAlbumService, AlbumEfService>();

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

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

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

services.AddScoped<IUserService, UserService>();

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

services.AddScoped< UserService>();

services.AddScoped( typeof( UserService));

 

 

 

 

  • 点赞
  • 收藏
  • 分享
  • 文章举报
覃鸿宇 发布了17 篇原创文章 · 获赞 6 · 访问量 348 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: