使用Task并行库实现“只有一个”和“非并行”语义

时间:2010-08-31 22:58:38

标签: c# .net task-parallel-library

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

选项1)此密钥中只有一个待处理。例如,可以使用ASP.NET MVC为缩略图图像排队单个渲染,无论图像Url被击中多少次。只有一个运行,所有其他请求都等待那个请求完成。

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

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

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

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

是否有人使用TPL实现了与此类似的任何内容,如果是这样,您在Task,TaskScheduler和TaskFactory类中采用了什么方法?

2 个答案:

答案 0 :(得分:1)

这个问题类似于我在ReactiveXaml中解决的问题,尽管我也记得先前的请求。看一下QueuedAsyncMRUCache(以及它的blog entry)的代码 - 这段代码将TPL与Reactive Extensions结合起来完成这类工作,但它确保了第二个请求的重要保证。相同的密钥将阻止第一个正在进行的请求而不是发出另一个请求。

答案 1 :(得分:1)

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

  1. 创建一个包装类 - 比如KeyProcessor来为一个键排列项目。
  2. KeyProcessor.Run()方法将能够满足您所需的任何排队语义。从本质上讲,它会为任何待处理的工作寻找内部队列,然后继续按顺序执行。
  3. 维护KeyProcessor对象的字典。
  4. 对于任何新任务,请在字典中查找相同的密钥。如果不存在则添加它。将任务排在队列上。如果它没有运行,则使用“运行方法”作为操作,使用TPL计划它。
  5. 使用ContinueWith来安排维护者任务 - 例如,每当完成执行KeyProcessor.Run的任务时,继续任务可以检查是否已为同一个密钥安排了任何其他任务(因为它已完成)并再次启动或删除来自字典。
  6. 以上所有内容在线程同步点都很棘手,而不是System.Collections.Concurrent命名空间中存在的一些有趣的集合。这将使上述逻辑更加简单。例如,ConcurrentDictionary.GetOrAdd 将允许以线程安全的方式查找和/或添加KeyProcessor对象。