在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各类经常使用场景,可是感受有部份内容尚未完善,在这里补充一下。html
在使用 Task 进行基于队列的异步任务(TAP)的时候,对于刚入门的同窗来讲,只是简单的了解了使用 Task 能够在后台处理异步任务,可是对于阻塞调用可能还有有一些不太明白,异步任务默认是不阻塞的执行过程,当一个 Task 被建立出来的时候,并无被压入队列中,而是开始执行的时候,才会进入队列中;执行一个异步任务能够设置等待git
[HttpGet] public async Task<string> Get() { string result = string.Empty; await Task.Run(() => { result = "Hello World!"; }); return result; }
上面的异步方法 Get() 内部执行了一个 Task,为了保持方法在返回的时候可以给变量 result 设置值,这里使用了 await 等待任务完成,在任务未完成前,即 result 未被设置值 Hello World! 前,该接口将一直阻塞,直到任务完成。github
[HttpGet("WaitTest")] public string WaitTest(int id) { string result = string.Empty; var waitTask = Task.Run(() => { result = "Hello World!"; }); waitTask.Wait(TimeSpan.FromSeconds(5)); return result; }
上面的代码定义了一个 TAP ,waitTask 使用了 Wait() 方法进行等待并传入一个时间,表示等待 5 秒中后退出阻塞过程,多线程
[HttpGet("WaitToken")] public string WaitToken(int id) { var result = string.Empty; CancellationTokenSource cts = new CancellationTokenSource(); var taskToken = Task.Run(() => { cts.CancelAfter(TimeSpan.FromSeconds(1)); Task.Delay(2000).Wait(); result = "Hello World!"; }); taskToken.Wait(cts.Token); return result; }
上面的任务 taskToken ,则使用了取消令牌,当令牌没有收到取消通知的时候,该任务将一直等待, taskToken 任务内部指示取消令牌 1 秒后取消,同时,任务内部使用 Task.Delay 阻塞 2 秒,这很特别,这种设置使得 taskToken 任务将引起任务取消的异常而致使没法给 result 变量进行值设置,若是你对取消令牌不太了解,建议阅读我以前的文章 Asp.Net Core 轻松学-多线程之取消令牌app
在同步方法中,咱们能够很是容易的建立一个 Task 任务,特别是 .Net Core 提供了 Task 这么方便的使用方式的状况下,在某些场景下,就会出现一些意想不到的问题,个人忠告是:在使用 TAP 的时候,尽量的使用可等待的任务,特别是须要注意不要在 TAP 中运行一些耗时较长的任务,好比批量处理数据、事务过程等等,若是真的是须要有这一类型的任务须要使用 Task 进行处理,那么个人建议是,将这些任务缩小,而后尽快的结束,好比,你可使用消息队列来执行批量处理数据,而 Task 的任务则缩小至把处理条件丢到消息队列中,这样的解耦才是正确的选择,长时间运行于后台的 TAP,经常致使许多问题,好比消息冒泡、服务重启,都有可能会中断 TAP 线程,要知道,全部的 TAP 都是后台线程,当主进程退出的时候,后台线程也将被清理异步
在 TheadPool 内部,提供了一个排队的方法,当线程池资源可用后,将会自动的执行该队列,这样作的好处显而易见,就是你能够经过定义一系列的任务,而后等待线程池去按顺序处理它,这个排队的过程本质上就是队列async
[HttpGet("TaskQueue")] public bool TaskQueue() { var inQueues = ThreadPool.QueueUserWorkItem(ThreadProc); return inQueues; } private void ThreadProc(Object stateInfo) { Console.WriteLine("此任务来自线程池队列执行"); }
上面的代码中,在 TaskQueue() 内部使用 ThreadPool.QueueUserWorkItem() 将方法 ThreadProc(Object stateInfo) 压入队列中,并返回一个值:inQueues ,该值指示任务压入队列是否成功,在 .Net Core 中,ThreadPool.QueueUserWorkItem() 提供了 3 个方法重载,能够按需使用;使用重载方法,甚至能够在压入任务的时候传入参数调用,相似下面的代码测试
[HttpGet("TaskQueue")] public bool TaskQueue() { var inQueues = ThreadPool.QueueUserWorkItem(ThreadProc); var inQueuesSecond = ThreadPool.QueueUserWorkItem(ThreadProc, "这是一条测试消息"); return inQueues; } private void ThreadProc(Object stateInfo) { Console.WriteLine(stateInfo); }
若是业务须要,该参数还可传入实体对象hybrid-app
使用混合方法执行 TAP 的好处是,能够隐藏业务实现细节,提供统一调用入口线程
[HttpGet("HyBrid")] public Task<string> HyBrid([FromQuery]string value) { return HyBridInternal(value); } private async Task<string> HyBridInternal(string value) { await Task.Run(() => { Console.WriteLine(value); }); return "Your Input:" + value; }
混合方法,不要被它的名头唬住,你能够把它当作一个方法重载,这样作的好处是,当发生异常是,你能够快速的定位到出现异常的方法,而不是任务
本文的内容只是上一篇文章的补充,因此这里就不在放入执行结果,可是示例代码仍是同样的奉上
https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.TaskSecond