我有一个类,其中包含一个BlockingCollection<Task>
用于对多个任务进行排队以按顺序运行(先进先出)的类。
队列本身是在一个单独的长时间运行的任务上启动的。
public class TaskQueue
{
private readonly BlockingCollection<Task> _queue = new BlockingCollection<Task>();
public TaskQueue()
{
Task.Factory.StartNew(() =>
{
ProcessQueue();
}, TaskCreationOptions.LongRunning);
}
private async Task ProcessQueue()
{
foreach (var task in _queue.GetConsumingEnumerable())
await task;
}
...
}
当应用程序启动时,我创建了许多实例,TaskQueue
因为我需要为应用程序的不同组件使用不同的队列。
我看到的问题是,即使是ProcessQueue()
在 LongRunning 任务上启动的.NET Long Running Task
,但在任务的第一次等待之后,它会返回,即.NET ThreadPool Worker
不再是长时间运行的任务。
这会导致所有实例TaskQueue.ProcessQueue
结束.NET ThreadPool Workers
(在第一个等待之后),然后导致应用程序启动新任务的速度非常慢,因为它已经达到了并发运行的最大数量.NET ThreadPool Workers
(我相信这被设置为并发运行的数量)机器拥有的核心(在我的例子中是 8),之后它只会.NET ThreadPool Workers
每秒左右创建新的核心。
所以我的问题是:
- 有没有办法返回长时间运行的任务?
Task.Factory.StartNew
或者我应该用新线程替换?我相信这会解决问题,但不确定是否有更好的方法。
是的,首先不要离开长时间运行的任务。
ProcessQueue
您可以更改要返回的签名,void
而不是像Task
这样:这样,
LongRunning
任务将在等待消耗任务和等待消耗的任务完成之间交替。同一个线程将完成所有等待。顺便说一句,原始
async
版本ProcessQueue
以及此处建议的void
版本都没有做任何建设性的事情。他们没有处理任何事情,他们只是在等待。我假设您省略了该方法的“过程”部分,以保持示例简单。否则,这ProcessQueue
将只是徒劳的练习。