1

使用以下操作的 KEY 实施任务的最佳方法是什么:-

选项 1) 只有一个密钥是未决的。例如,可用于从 ASP.NET MVC 为缩略图图像排队单个渲染,无论图像 Url 被点击多少次。只有一个运行,所有其他请求等待那个完成。

选项 2) 具有相同键的所有项目必须按顺序执行。例如,可用于确保从后备存储获取文件到本地缓存的操作不会同时尝试将文件获取到缓存。选项 1 是一种特殊情况,其中具有相同键的后续操作被简单地丢弃(通常只保存文件存在检查)。

我有一个现有的 WorkQueue 可以处理这两种情况(以及 Apartment 状态、ThreadPriority 设置和最大并行度)。TPL 似乎是替代它的最佳解决方案,并将带来改进的取消选项。

带有延续的嵌套任务看起来很有希望,但维护当前排队任务的字典很快就会在 TaskFactory 和 TaskScheduler 类之间变得混乱。从 Task 继承也是有问题的,因为 TaskFactory 和 TaskScheduler 在 Task 上都不是通用的。

大多数任务并行示例假设任务集是提前知道的。在这种情况下,新任务一直被添加,需要根据请求的操作和传入的密钥被丢弃或链接到现有任务上。

有没有人使用 TPL 实现过类似的东西,如果有,你在 Task、TaskScheduler 和 TaskFactory 类中采用了什么方法?

4

2 回答 2

1

这个问题类似于我在ReactiveXaml中解决的问题,尽管我的也记住了以前的请求。看一看QueuedAsyncMRUCache的代码(及其博客条目)——这段代码结合了 TPL 和反应式扩展来完成这种事情,但它保证了对同一密钥的第二次请求将在第一个飞行中的请求,而不是发出另一个请求。

于 2010-08-31T23:13:49.057 回答
1

也许,我能想到的一种方法是

  1. 创建一个包装类 - 比如说 KeyProcessor 来为一个键排队。
  2. KeyProcessor.Run() 方法将能够处理您需要的任何排队语义。本质上,它会为任何待处理的工作寻找内部队列,然后继续按顺序进行。
  3. 维护 KeyProcessor 对象的字典。
  4. 对于任何新任务,请在字典中检查相同的键。如果不存在则添加它。排队任务就可以了。如果它没有运行,则使用 Run 方法作为操作使用 TPL 对其进行调度。
  5. 使用 ContinueWith 来安排维护者任务 - 例如,每当 Task 执行 KeyProcessor.Run 完成时,延续任务可以检查是否有更多任务为同一个键安排(因为它已经完成)并再次启动它或从字典中删除。

从线程同步点开始,以上所有内容都会很棘手,而不是因为System.Collections.Concurrent命名空间中存在一些有趣的集合。这将使上述逻辑更加简单。例如,ConcurrentDictionary.GetOrAdd将允许以线程安全的方式查找和/或添加 KeyProcessor 对象。

于 2010-09-01T06:18:50.947 回答