C#如何最大化特定代码段不发生上下文切换的机会?

3

我在我的应用程序中有一段时间关键的代码。我将运行它的线程设置为最高优先级 - 这是我能做的最多的。

有没有建议如何使此线程中运行的代码部分尽可能少地被中断(发生更少的上下文切换)?

这段代码并不复杂。我用内联代码替换了所有方法调用,并且没有使用任何高级功能(例如没有使用LINQ)。大多数操作都是算术运算。只有一个字符串比较(我正在考虑如何摆脱它)。一半的数学运算涉及整数,另一半涉及双精度浮点数。

这段代码是x86 .NET 4 C#编写的。在单个Xenon X3450 W2008R2服务器上运行单个应用程序。

(不幸的是,数据来自不支持x64的第三方API(讨厌它!))

我希望和有经验的开发人员进行成熟的讨论。

P.S. 服务器没有页面文件,因此也不会发生硬页错误(没有不需要的IO操作)。


请不要在标题中重复标签。 - John Saunders
标题对我很重要。虽然这似乎并不总是正确的,但当我在标题中加入C#时,我的意思比标题的语义更深远。如果您想请直接与我联系,我会进行解释。你改变了我所有的帖子真的让我很烦恼。你是谁? - Boppity Bop
你正在使用Server Core吗?它比完整安装具有更低的内存占用和显著较少的线程使用。 - Warren Rumak
嗯...我刚才也在考虑同样的事情!但不幸的是,这个盒子已经安装满了,并且现在在远程机房。要把它拿回来并重新安装需要很长时间...我犹豫是否使用核心安装,因为我不知道如何使用它! :) - Boppity Bop
2个回答

2
在上下文切换方面唯一需要担心的是阻塞线程。因此,使用LINQ(即LINQ-to-objects,显然不包括LINQ-to-SQL或其他会导致阻塞的操作)应该没有问题!任何形式的算术运算、调用方法等都不会阻塞线程,因此对上下文切换没有影响。
另一个影响上下文切换的因素就是你提到的优先级。但这不仅涉及线程优先级,还包括进程优先级。你可以使用SetPriorityClass将进程优先级提高到“ABOVE_NORMAL_PRIORITY_CLASS”(我不建议设置得比这更高),然后将线程优先级也设为Above Normal。
然而,一般来说,优先级只有在涉及到时间问题时才真正有用(也就是确保您的进程尽可能快地响应外部输入(网络、用户输入、磁盘I/O))。除非同时运行其他CPU密集型进程,否则它实际上对线程的实际吞吐量几乎没有影响。但如果是这种情况,那么调整优先级不会是一个可行的长期解决方案。这是因为您会发现将其中一个进程设置为更高的优先级会完全使其他进程饿死,它们永远不会运行。

因此,在调整线程和进程优先级之前,我建议您仔细考虑一下,并且像往常一样进行测试!


谢谢。该进程已经以实时优先级运行。你是说除非线程在某些东西上被阻塞,或者具有最高优先级的线程需要CPU,否则不会发生上下文切换? - Boppity Bop
我知道什么是阻塞。我消除了方法调用,使该部分更快。这将进而为我提供更好的不被中断的机会。 - Boppity Bop
@Bobb:没错,具有最高优先级的线程总是在其他线程之前被调度。它不会被切换到优先级较低的线程(除非它被阻塞)。 - Dean Harding

1

如果你使用非托管的WINAPI代码,SetThreadPriority函数也支持THREAD_PRIORITY_TIME_CRITICAL(高于THREAD_PRIORITY_HIGHEST)。

此外,提高线程所在进程的优先级也是值得考虑的(实际优先级取决于线程和进程优先级的组合)。

你还应该避免在线程上进行I/O调用(可能会阻塞)。甚至可以将其推向一个可能荒谬的极端,即避免在其他线程上进行I/O调用(这可能会暂时提高这些线程的优先级)。


代码的关键部分没有调用任何方法(甚至没有访问对象的属性)。更不用说IO了!我不能将整个线程设为非托管,因为它在计算开始时从托管队列中读取数据,并在结束时将结果发布到托管对象中。这样我最终会得到一个完全非托管的应用程序。在那种情况下,我宁愿使用带有实时内核的Linux。但是用C++和Linux完成我在C#中做的工作需要我花费2-3个月的时间,而不是3周。 - Boppity Bop
@Bobb,您还可以尝试降低其他线程的优先级,以减少它们抢占关键线程的可能性。 - ChrisW
谢谢Chris,这个也完成了。我的应用程序中有大约7个工作线程和由.NET创建的大约15个其他线程...我今天将转移到控制台版本(现在我只有一个小WPF窗口),希望能进一步减少线程数量。 - Boppity Bop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接