.NET Standard 2.0写的类库
代码思路大致如下
public class MyService { public ConcurrentQueue<Task> TaskList = new ConcurrentQueue<Task>(); public async Task<int> Run() { var task = new Task<int>(Mission, "ffff"); list.Enqueue(task); return await task; } public int Mission(object para) { //do someting return num; } }
TaskList 会在外部的某个地方异步调用,并启动列队里的Task
这种写法在控制台引用程序里,执行 new MyService().Run().Result ,可以正常运行。
但是在MVC的项目里,同样的方法调用上面的代码,await task以后的代码无法被执行到,但是debug的时候mission内部的代码的确执行了。
请问这是什么原因,是我使用Task的姿势不对吗?
首先async await的死锁的问题LZ需要去了解下。
其次我理解LZ的需求是 初始化一个容器,装载一些需要任务 需要去异步执行。这里我认为完全没必要把Task装载到容器中。完全可以定义一个接口
public interface Mission
{
int Do(object para);
}
各类任务实现这个接口装载到容器中。取出来的时候再 Task.Run() 异步执行。
不知是否理解有误。
之前不知道是脑子抽了还是咋的,陷入了一个怪圈,竟然想到了创建无数task,然后异步起动,借此来实现任务调度这种奇葩的想法。更神奇的是最后东改西改的竟然实现了效果!
但是在一个压力测试下,直接就崩了。首先无数的task造成默认的线程队列阻塞,连一个最普通的stream异步读取string都要执行30S+,而且这个过程是雪崩式的。达到一个阈值以后就越来越卡,直到整个程序卡崩。
后来有点别的安排就有一段时间没有看这段代码。等之后再看,越看越觉得自己脑残。
代码现在已经重写过了,就是类似你提到的思路。容器本身并不存储task,而是存储运行task必要的一些值,然后做了一个任务调度,来动态的启动和关闭一些task,这些task的任务就是从容器中取值然后计算。
async/await的死锁 的确是学到新东西了,虽然可能不是本质上为啥MVC不能用那种奇葩方法的解释。这块以后再研究。
之后有机会,会把轮子开源的。 再次感谢
Task.Run 闪亮登场
public class MyService
{
public ConcurrentQueue<Task> TaskList = new ConcurrentQueue<Task>();
public async Task<int> Run()
{
var task = Task.Run<int>(() => Mission("ffff"));
TaskList.Enqueue(task);
return await task;
}
public int Mission(object para)
{
Console.WriteLine("Doing a mission");
return 1;
}
}
这样会让任务直接开始运行,因为需要控制可以同时执行Task的数量,所以才创建尝试通过创建这种没有运行的Task,然后再外部通过一个调度方法,来异步启动Task。
是不是我这种思路不太对?
@写代码的相声演员: 参考 awaitable Task based queue
你表演一个相声我就回答你