【发布时间】:2012-01-30 22:20:18
【问题描述】:
我们有一个非常高性能的多任务处理、近乎实时的 C# 应用程序。这种性能主要是通过使用本地调度程序在内部实施协作多任务来实现的。这通常称为微线程。在这个系统中,所有任务都通过队列与其他任务进行通信。
我们遇到的具体问题似乎只能通过 C# 不支持的第一类延续来解决。
特别是在处理队列的两种情况下会出现问题。每当任何特定任务在将项目放入队列之前执行一些工作时。队列满了怎么办?
相反,一个不同的任务可能会做一些工作,然后需要从队列中取出一个项目。如果该队列为空怎么办?
我们已经在 90% 的情况下解决了这个问题,方法是将队列链接到任务,以避免任务在出站队列已满或入站队列为空时被调用。
此外,某些任务被转换为状态机,因此它们可以在队列满/空时进行处理,并且无需等待即可继续。
真正的问题出现在一些极端情况下,其中任何一种解决方案都不切实际。这种情况下的想法是在该点保存堆栈状态并切换到不同的任务,以便它可以完成工作,然后在能够继续时重试等待的任务。
过去,我们试图让等待任务回调到调度中(递归),以允许其他任务稍后重试等待任务。然而,这导致了太多的“死锁”情况。
有一个自定义 CLR 主机的示例,使 .NET 线程实际上作为“光纤”运行,这实际上允许在线程之间切换堆栈状态。但现在我似乎找不到任何示例代码。此外,似乎需要一些相当复杂的事情才能让它正确。
有没有人有其他的创意想法如何在任务之间高效切换并避免上述问题?
是否有任何其他 CLR 主机提供此功能(商业或其他方式)?是否有任何附加的原生库可以为 C# 提供某种形式的延续?
【问题讨论】:
-
光纤模式 CLR 主机示例 -- 你可能指的是 Dino Viehland 的博客系列,从这里开始:blogs.msdn.com/b/dinoviehland/archive/2004/08/16/215140.aspx
-
Nit:死锁不是效率问题。这是一个正确性问题。 (另外,一个完整的未绑定队列和没有更多内存有什么区别?状态就是状态,必须存储在某个地方。)
-
我们在 C# 5 中添加了一种延续形式。虽然它们不完全是一流的调用/cc 风格的延续,但它们在道德上是等价的。查看“异步 CTP”的预览版。 msdn.microsoft.com/en-us/vstudio/gg316360.aspx。另请参阅 Stephen Toub 最近关于异步功能的性能特征的 MSDN 杂志文章。
-
@Wayne,异步 CTP 确实包含一些调度程序,但您不必使用它们。当你写
await something,something时,它会得到延续,这取决于它如何处理。所以,在我看来你只需要实现你自己的等待类型。 -
Mono 的 Continuations 似乎就是这样:一个 CLI VM 扩展,允许将任务“恢复”到给定状态。他们甚至有一个带有自己的调度程序类的微线程库。
标签: c# .net queue multitasking continuations