异步编程(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 modelTask<Album> GetByIdAsync(int id);//返回一个Album modelTask<Album> AddAsync(Album model);//无返回值的异步操作Task UpdateAsync(Album model);//无返回值的异步操作Task DeleteAsync(Album model);}
然后实现该接口:实现该接口中Task类
[code]public class AlbumEfService : IAlbumService{//声明一个只读字段,这里HeavyContext是一个数据库Modelprivate readonly HeavyContext _context;//依赖注入该modelpublic 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: Albumpublic async Task<ActionResult> Index(){var albums = await _albumService.GetAllAsync();return View(albums);}// GET: Album/Details/5public async Task<ActionResult> Details(int id){var album = await _albumService.GetByIdAsync(id);if (album == null){return RedirectToAction(nameof(Index));}return View(album);}// GET: Album/Createpublic 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私信关注