我希望以this问题为基础。
到目前为止,我有办法并行处理作业。我在控制台应用程序中运行它。我从db获得了50个工作,使用TPL DataFlow
处理它们,到目前为止一直很好。但我意识到,如果有一个工作需要一个小时来处理,其余的工作在15分钟内完成,控制台应用程序将继续运行一个小时而不处理任何进一步的工作。我无法将其更改为Windows服务,因此我必须让控制台应用程序处理新的作业,可能每15分钟检查一次。
我可以启动计时器,每15分钟检查一次新工作。如果数据库中有任何新作业,我需要添加到buffer block
,以便actionblock
可以处理它。问题是在添加前50个作业后,必须为缓冲区和操作块调用complete和completion.wait。所以我不能再向现有的缓冲区添加新的工作了。
我可以检查当前actionblock's
isCompleted属性,然后动态创建另一个buffer/actionblock
组合。基本上情况是,如果当前actionblock
仍然存在,请检查timer
上的新作业并创建新的buffer/actionblock
组合。这就是我打算做的事情。但在我走这条路之前,我能采取另一种方法来解决这个问题吗?
答案 0 :(得分:1)
如果我理解正确,你想要的只是一个不变的流动"要同时执行的作业,但是等待执行的作业不超过50个,您可以使用相同的ActionBlock
和BoundedCapacity
,并在可以的时候添加:
private static Task ProcessJobsAsync(CancellationToken cancellationToken)
{
var block = new ActionBlock<Job>(
job => job.Process(),
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount, // Or any other value that fits
BoundedCapacity = 50,
});
cancellationToken.Register(block.Complete);
var producer = Task.Run(async () =>
{
while (!cancellationToken.IsCancellationRequested)
{
foreach (var job in await GetJobsAsync())
{
await block.SendAsync(job,cancellationToken);
}
}
});
return Task.WhenAll(producer, block.Completion);
}
如果阻塞很慢,并且达到它,容量wait block.SendAsync(job,cancellationToken);
将异步等待,直到队列中的空间被清除为另一个作业。这样你总能找到要执行的工作。当您想要关闭应用程序(或取消操作)时,您可以使用CancellationToken