C#第一类继续通过C ++互操作或其他方式?

时间:2011-12-31 02:05:26

标签: c# .net queue multitasking continuations

我们拥有非常高性能的多任务处理,近乎实时的C#应用​​程序。这种性能主要通过在内部与本土调度程序一起实施协作式多任务处理来实现。这通常被称为微线程。在该系统中,所有任务都通过队列与其他任务进行通信。

我们遇到的具体问题似乎只能通过C#不支持的头等连续解决。

具体而言,问题出现在2个处理队列的案例中。每当任何特定任务在将项目放入队列之前执行某些工作时。如果队列已满,该怎么办?

相反,一个不同的任务可能会做一些工作,然后需要从队列中取出一个项目。如果该队列为空怎么办?

我们在90%的情况下通过将队列链接到任务来解决这个问题,以避免在任何出站队列已满或入站队列为空时调用任务。

此外,某些任务被转换为状态机,因此如果队列已满/空,它们可以处理并继续而无需等待。

真正的问题出现在一些边缘情况下,其中任何一种解决方案都是不切实际的。在这种情况下的想法是在该点保存堆栈状态并切换到另一个任务,以便它可以完成工作,然后在它能够继续时重试等待任务。

过去,我们尝试将等待任务调用回调度(递归)以允许其他任务进行,然后重试等待任务。然而,这导致了太多的“僵局”情况。

在自定义CLR主机的某个地方有一个示例,使.NET线程实际上作为“光纤”运行,这实际上允许在线程之间切换堆栈状态。但现在我似乎无法找到任何示例代码。此外,似乎需要一些重要的复杂性才能做到正确。

有没有人有任何其他创意想法如何有效地切换任务并避免上述问题?

是否有其他CLR主机提供此功能,商用或其他?是否有任何附加本机库可以为C#提供某种形式的延续?

5 个答案:

答案 0 :(得分:2)

C# 5 CTP,它对使用新async关键字声明的方法执行继续传递样式转换,并在使用await关键字时执行基于延续传递的调用。

这实际上不是一个新的CLR功能,而是一组指令,供编译器对代码执行CPS转换,以及一些用于操作和调度延续的库例程。 async方法的激活记录放在堆而不是堆栈上,因此它们不依赖于特定的线程。

答案 1 :(得分:1)

不,不去上班。 C#(甚至IL)是一种过于复杂的语言,无法以一般方式执行此类转换(CPS)。你能得到的最好的就是C#5将提供的。也就是说,您可能无法通过更高阶循环/迭代来中断/恢复,这实际上是您希望从通用可再生延续中获得。

答案 2 :(得分:1)

由于压力下的问题,已从CLR的v2中删除了光纤模式,请参阅:

据我所知,纤维支持尚未重新添加,虽然从阅读上述文章可以可能再次添加(但事实上没有提及6至7年的主题让我相信它不太可能)。

FYI光纤支持旨在为使用光纤(如SQL Server)的现有应用程序提供一种方式来托管CLR,使其能够最大限度地提高性能,作为方法允许.Net应用程序创建大量线程 - 短纤维中的不是解决问题的灵丹妙药,但是如果你有一个使用光纤的应用程序希望托管CLR,那么托管主机API确实为CLR提供了与您的应用程序“良好协作”的方法。关于此的一个很好的信息来源是managed hosting API documentation,或者研究SQL Server如何托管CLR,其中有几篇内容丰富的文章。

另请快速阅读Threads, fibers, stacks and address space

答案 3 :(得分:1)

实际上,我们决定采用这个方向。我们正在使用带有Message Passsing的Observer模式。我们构建了一个本地库,用于处理类似于Erlang进程的“代理”之间的所有通信。稍后我们将考虑使用AppDomains来更好地将代理彼此分开。设计思想借鉴了Erlang编程语言,该语言具有极其可靠的多核和分布式处理。

答案 4 :(得分:0)

您的问题的解决方案是使用无锁算法,允许至少一个任务的系统范围进展。您需要使用依赖于CPU的内联汇编程序来确保您使用原子CAS(比较和交换)。维基百科有article以及由Douglas Schmidt描述的book称为“面向模式的软件架构,并发和网络对象的模式”的模式。我不清楚你将如何在dotnet框架下做到这一点。

解决问题的其他方法是使用发布订阅者模式或可能的线程池。

希望这有用吗?