2011-07-21 37 views
5

我有几个想要在后台执行的动作,但它们必须一个接一个地同步执行。使用Task.ContinueWith创建执行队列?

我想知道是否使用Task.ContinueWith方法来实现这一点是个好主意。你有没有预见到这个问题?

我的代码看起来是这样的:

private object syncRoot =new object(); 
private Task latestTask; 

public void EnqueueAction(System.Action action) 
{ 
    lock (syncRoot) 
    { 
     if (latestTask == null) 
      latestTask = Task.Factory.StartNew(action); 
     else 
      latestTask = latestTask.ContinueWith(tsk => action()); 
    } 
} 

回答

5

这应该作为设计(使用的事实是TPL将立即安排延续,如果相应的任务已经完成)。

个人在这种情况下,我会使用专用线程使用并发队列(ConcurrentQueue)来绘制任务 - 这更明确,但更容易解析读取代码,特别是如果你想知道,即有多少任务目前正在排队等。

+0

一个改进是围绕ConcurrentQueue使用BlockingCollection。然后可以派发一个Task/Worker线程,该线程只使用foreach对阻塞集合进行操作。 foreach将“挂起”,直到将新项目添加到队列中,或者在阻塞集合上调用CompleteAdding()。 –

7

这有一个缺陷,我最近发现自己,因为我也使用这种方法确保任务顺序执行。

在我的应用程序中,我有成千上万的这些小型队列的实例,并很快发现我有内存问题。由于这些队列经常处于闲置状态,因此我长时间保持最后完成的任务对象并防止垃圾收集。由于上次完成的任务的结果对象通常超过85,000字节,因此将其分配给大对象堆(在垃圾回收期间不执行压缩)。这导致了LOH的碎片化,并且该过程的规模不断扩大。

作为一种避免这种情况的手段,您可以安排一个禁止任务,直到您的锁定中的实际任务完成。对于一个真正的解决方案,我需要转移到另一种控制调度的方法。

0

我用这个片段,似乎得到它按设计工作。 在我的情况下,实例的数量没有运行到数千个,而是以单个数字运行。 尽管如此,目前还没有问题。

我会对ConcurrentQueue示例感兴趣,如果有的话?

谢谢

+0

对于一个超级简单的队列,这仍然适合我。但是,我已经开始使用[Dataflow](http://msdn.microsoft.com/zh-cn/library/hh228603(v = vs.110).aspx)更多的涉及任务队列。 – lukebuehler