长时间运行的任务行为

问题描述 投票:0回答:1

我有一个包含

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()
是在长时间运行的任务
.NET Long Running Task
上启动的,在任务的第一次等待之后,它会返回到
.NET ThreadPool Worker
,即不再是长时间运行的任务。

这会导致

TaskQueue.ProcessQueue
的所有实例都以
.NET ThreadPool Workers
结束(在第一次等待之后),然后导致应用程序启动新任务的速度非常慢,因为它已达到并发运行的最大数量
.NET ThreadPool Workers
(我相信这被设置为机器拥有的核心数,在我的例子中是 8),之后它只会每秒左右创建新的
.NET ThreadPool Workers

所以我的问题是:

  1. 有没有办法返回长时间运行的任务?
  2. 或者我应该用新线程替换
    Task.Factory.StartNew
    ?我相信这可以解决问题,但不确定是否有更好的方法。
c# task blockingcollection long-running-task
1个回答
0
投票

有没有办法返回长时间运行的任务?

是的,首先不要离开长时间运行的任务。您可以更改

ProcessQueue
的签名以返回
void
而不是
Task
,如下所示:

private void ProcessQueue()
{
    foreach (var task in _queue.GetConsumingEnumerable())
        task.GetAwaiter().GetResult();
}

这样,

LongRunning
任务将在等待消耗任务和等待消耗的任务完成之间交替。同一个线程将完成所有等待。

顺便说一句,

async
的原始
ProcessQueue
版本,以及此处建议的
void
版本,都没有做任何建设性的事情。他们没有处理任何事情,他们只是在等待。我假设您省略了该方法的“过程”部分,以保持示例简单。否则,
ProcessQueue
将只是徒劳的练习。

© www.soinside.com 2019 - 2024. All rights reserved.