【发布时间】:2012-12-11 11:32:34
【问题描述】:
我有以下场景
- 我正在编写一个处理文件(作业)的服务器
- 一个文件有一个“前缀”和一个时间
- 文件要按时间处理(旧文件优先)但也要考虑前缀(不能同时处理具有相同前缀的文件)
- 我有一个线程(带定时器的任务)监视目录并将文件添加到“队列”(生产者)
- 我有几个从“队列”(消费者)获取文件的消费者——他们应该符合上述规则。
- 每个任务的作业都保存在某个列表中(这表明了约束)
- 有多个消费者,消费者数量在启动时确定。
其中一个要求是能够优雅地停止消费者(立即或让正在进行的进程完成)。
我沿着这条线做了一些事情:
while (processing)
{
//limits number of concurrent tasks
_processingSemaphore.Wait(queueCancellationToken);
//Take next job when available or wait for cancel signal
currentwork = workQueue.Take(taskCancellationToken);
//check that it can actually process this work
if (CanProcess(currnetWork)
{
var task = CreateTask(currentwork)
task.ContinueWith((t) => { //release processing slot });
}
else
//release slot, return job? something else?
}
取消标记源位于调用方代码中,可以取消。有两个是为了能够在不取消正在运行的任务的同时停止排队。
我厌倦了将“队列”实现为包装“安全”SortedSet 的 BlockingCollection。除了我需要找到与约束匹配的新工作的情况外,一般的想法工作(按时间排序)。如果我将工作返回队列并尝试再次接受,我将得到相同的。
可以从队列中取出作业,直到我找到合适的作业,然后返回“非法”作业,但这可能会导致其他消费者处理乱序作业时出现问题
另一种选择是传递一个简单的集合和一种锁定它的方法,然后根据当前的约束锁定并进行简单的搜索。同样,这意味着编写可能不是线程安全的代码。
还有其他可以提供帮助的建议/指针/数据结构吗?
【问题讨论】:
-
最早可以处理此类作业的时间是第一个作业完成时。所以工人也可以处理下一个。因此,将作业列表放入队列中,而不仅仅是作业,列表中的每个作业都有相同的前缀。
-
@HansPassant - 我考虑过 - 有一些每个进程的本地队列,但不确定这不是 100% 正确 - 拥有相同的消费者队列下一个具有相同前缀的作业可能会违反处理方式-时间要求 - 我需要考虑一下,看看它是否适用于所有约束。无论如何-感谢您的意见。
-
@HansPassant - 你指出的确实是正确的。我最终在每个“专业”消费者中实现了一个本地队列,并且需要在他们的队列上“本地”排队额外的作业。如果消费者“错过”了排队的文件(例如,在消费者存在处理循环后完成的时间之间添加了作业),它将返回到一般队列并由任何可用的消费者处理。我可以将评论标记为答案吗?
-
@TomerCagan 请看我编辑的answer。希望它有助于简化您的解决方案。
标签: c#-4.0 concurrency task-parallel-library concurrent-programming