能否在“保留”的CPU核心上运行代码?

4

简化背景:

我的应用程序运行了很多任务。其中大部分是CPU密集型的。
一个任务(实际上是一个在循环中运行的单个线程,监听来自网络的数据包),非常“实时”。更有趣的是,该线程是使用pinvoke调用的本地代码。

问题:

当有大量流量显示时,任务正在努力工作,所有核心都达到了最大值。当发生这种情况时,“实时”线程(在100% CPU核心上运行),开始丢失数据包,因为它没有足够的CPU时间。

问题:

是否可能以某种方式“保留”一个核心供“实时”线程使用,并将所有其他线程(任务)限制在其他核心上?

  • 当然,还有其他正在运行的进程,也会消耗CPU时间,但让我们假设它们只消耗很少而且恒定的资源。
  • 这是一个真正的问题,可以通过“增加更多的CPU”来解决......不是一个选项......

编辑 - 回答许多有用的评论:

  • 我们使用WinPcap捕获所有数据包,这可能是很多(很多)。
  • “实时”线程并不是真正的“实时”(我认为“实时”是针对进程的 - 在.net中,ThreadPriority使用“Normal”,“AboveNormal”等)
  • “实时”线程按顺序调用WinPcap,一个数据包接一个数据包。我们怀疑由于它被饥饿到足够程度,它无法跟上,因此WinPcap的缓冲区溢出了。

2
为什么不简单地提高“任务”的优先级呢? - Some programmer dude
1
是的 - 我不明白。监听网络数据包通常不会占用太多CPU资源。你有100GB的网络吗? - Martin James
你是否正在使用UDP或类似的协议,其中数据包可能会丢失?如果是这样,提高网络线程的优先级似乎是更好的选择,正如@JoachimPileborg所建议的那样。 - Martin James
1
@JoachimPileborg:如果它(在Windows中)确实是实时线程,那么您无法将优先级提高到更高。但是,非实时线程也不会窃取核心。因此,我怀疑bug只是线程优先级实际上不是实时的。 - MSalters
2个回答

2
您可以为进程和线程指定亲和掩码。这允许您阻止调度程序使用特定的处理器。所以,您可以将一个线程的线程亲和掩码设置为单个处理器,并将所有其他线程的线程亲和掩码设置为除保留处理器之外的所有处理器。由于 .net 使您免受直接创建系统线程的影响,因此实际上不太容易对所有系统线程施加必要的掩码。
说服调度程序给予您的关键线程特殊待遇的另一种方法是提高其优先级。这是一件需要非常小心和深思熟虑的事情。然而,这是一种更简单的方式,可以确保您的线程永远不必等待您进程中的其他线程。
也许为您的应用程序使用少于处理器数量的线程,但为关键工作创建一个专用线程会更好。这样,您可以避免任何亲和掩码或优先级欺诈,并让系统的线程调度程序为您完成工作。

1
我相信你误解了问题的确切本质,尽管你的解决方案是正确的。问题不在于数据包监听线程以100%的速度运行,而在于数据包监听线程与其他任务线程共享一个核心,导致CPU资源被耗尽。因此,将其放置在单独的核心上,并让所有其他线程在所有其他核心上运行,将有助于减少数据包丢失,正如你所说的那样。 - Eight-Bit Guru
@Eight-BitGuru - 没错。 - seldary
1
@Eight的答案描述了如何做到这一点。 - David Heffernan
@seldary,可能需要将网络中断处理与专用核心绑定。我并不确定这种亲和力调整会以积极的方式影响总吞吐量,因为它会将其他应用程序可用的核心数量减少一个。如果您尝试了这个方法,并且实际上确实提高了整体性能,我很想听听您的经验。 - Martin James
当线程在收到信号后变为就绪状态,例如网络线程在数据可用时,通常会被动态地提高优先级,并应立即运行。我并不确定您是否已经确定了数据包丢失问题的根本原因: - Martin James
显示剩余4条评论

1
是的。这个概念被称为"处理器亲和性",在进程级别和线程级别都存在。它有点难以调用,但并不可怕: 如何在.NET中设置处理器亲和性? 请注意,您必须为所有可见的线程设置亲和性。但是,您并不是唯一创建线程的人——像ThreadPool和GC这样的东西也有一些线程。我不建议您去乱改那些线程,但ProcessThread类不会阻止您这样做。

你会如何确保托管进程中的所有本地线程都具有必要的掩码?是否有通知可以订阅,每当系统线程被创建时就会收到通知? - David Heffernan
@DavidHeffernan 没有这样的通知。要么代码在创建时执行,要么您可以定期轮询。 - Marc Gravell

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