How do I spawn threads on different CPU cores?假设我有一个使用C#编写的程序,该程序的计算量很大,例如将WAV文件列表编码为MP3。 通常,我会一次对文件进行编码,但比方说,我希望程序计算出我拥有多少个CPU内核,并在每个内核上增加一个编码线程。 因此,当我在四核CPU上运行程序时,程序会确定它是四核CPU,计算出有四个内核可以使用,然后产生四个用于编码的线程,每个线程都在自己的单独线程上运行 中央处理器。 我该怎么做? 如果内核分散在多个物理CPU上,这会有什么不同吗? 例如,如果我有一台装有两个四核CPU的机器,是否有任何特殊考虑,或者两个模具中的八个内核在Windows中是否被认为是相等的? 别那么做。 而是使用线程池。线程池是框架的一种机制(实际上是一个类),您可以查询新线程。 当您请求一个新线程时,它将为您提供一个新线程或使工作排队,直到释放线程为止。这样,框架负责决定是否应根据当前CPU的数量创建更多线程。 编辑:此外,正如已经提到的,操作系统负责在不同的CPU之间分配线程。 它不一定像使用线程池那样简单。 默认情况下,线程池为每个CPU分配多个线程。由于涉及到您正在执行的工作的每个线程都具有成本(任务切换开销,CPU的非常有限的L1,L2和L3高速缓存的使用等),因此,要使用的最佳线程数为<=可用CPU的数量-除非每个线程都向其他计算机请求服务-诸如高度可扩展的Web服务。在某些情况下,尤其是那些涉及硬盘读写比CPU活动更多的情况,使用1个线程实际上要比使用多个线程更好。 对于大多数应用程序,当然对于WAV和MP3编码,应该将辅助线程的数量限制为可用CPU的数量。这是一些C#代码来查找CPU的数量:
不幸的是,这并不像限制CPU数量那么简单。您还必须考虑硬盘控制器和磁盘的性能。 真正找到最佳线程数的唯一方法是尝试错误。当您使用硬盘,Web服务等时,尤其如此。使用硬盘时,最好不要在四核处理器CPU上使用所有四个处理器。另一方面,对于某些Web服务,您可能最好每个CPU发出10个甚至100个请求。 对于托管线程,执行此操作的复杂度要比本地线程高。这是因为CLR线程没有直接绑定到本机OS线程。换句话说,CLR可以根据需要将托管线程从本机线程切换到本机线程。提供函数Thread.BeginThreadAffinity可以将托管线程与本机OS线程锁定在一起。到那时,您可以尝试使用本机API来赋予基础本机线程处理器亲和力。正如每个人在这里建议的那样,这不是一个好主意。实际上,有文档表明,如果线程仅限于单个处理器或内核,则可以减少处理时间。 您还可以浏览System.Diagnostics.Process类。在这里,您可以找到一个函数来枚举ProcessThread对象作为ProcessThread对象的集合。此类具有设置ProcessorAffinity或什至设置首选处理器的方法-不确定是什么。 免责声明:我曾经遇到过类似的问题,我认为CPU的利用率不高,并对此进行了大量研究。但是,根据我阅读的所有内容,似乎也不是一个好主意,正如此处发布的评论所证明的那样。但是,它仍然很有趣,并且可以进行实验学习。 尽管我同意这里的大多数答案,但我认为值得添加新的考虑因素:Speedstep技术。 当在多核系统上运行CPU密集型单线程作业时(在我的情况下,它是在Windows Server 2012下具有6个真实核心(12个带有HT的)的Xeon E5-2430),该作业分散在所有12个核心中,使用每个核心的约8.33%,并且永远不会触发速度提升。 CPU保持在1.2 GHz。 当我将线程关联性设置为特定的内核时,它使用了该内核的100%左右,从而导致CPU在2.5 GHz时最大输出,使性能提高了一倍以上。 这是我使用的程序,它只是循环增加变量。当使用-a调用时,它将亲和力设置为核心1。亲和力部分基于该文章。
结果:
如任务管理器所示,处理器速度类似于CPU-Z报告的速度:
您绝对可以通过在程序内部编写例程来完成此操作。 但是,您不应该尝试这样做,因为操作系统是管理这些内容的最佳人选。我的意思是用户模式程序不应尝试这样做。 但是,有时可以做到(对于真正的高级用户),以实现负载平衡,甚至找出真正的多线程多核问题(数据竞速/缓存一致性...),因为不同的线程将真正在不同的处理器上执行。 话虽如此,如果您仍然想要实现,我们可以通过以下方式实现。我正在为您提供(Windows OS)的伪代码,但是它们也可以在Linux上轻松完成。
在调用上述例程之后,线程将始终以以下方式执行:
有关更多信息,请参阅手册/ MSDN以了解有关这些概念的更多信息。 您不必担心自己这样做。我有在双四核计算机上运行的多线程.NET应用程序,无论线程是如何启动的(无论是通过ThreadPool还是手动启动),我都能在所有内核上看到均匀的工作分配。 您无法执行此操作,因为只有操作系统才能执行此操作。如果您决定的话.....那么将很难编写应用程序代码。因为那样,您还需要注意处理器间的通信。关键部分。对于每个应用程序,您都必须创建自己的信号灯或互斥锁……操作系统自己可以对它们提供通用的解决方案。
在不同内核之间拆分线程是操作系统的工作,当线程使用大量CPU时间时,它将自动执行。不用担心至于要找出您的用户有多少个内核,请在C#中尝试 每个线程通常由操作系统本身处理...因此在一个4核系统上生成4个线程,操作系统将决定要在哪个内核上运行,每个内核通常是1个线程。 您不应该(如上所述)尝试自己分配这类内容的原因之一是,您只是没有足够的信息来正确地进行处理,尤其是在NUMA等方面。 如果您有一个要运行的线程,并且有一个内核处于空闲状态,则内核将运行您的线程,请不要担心。 |