为什么C#中的multithreading不能达到100%的CPU?

我正在研究一个处理许多请求的程序,它们都没有超过50%的CPU( 目前我正在研究双核 )。 所以我为每个请求创建了一个线程,整个过程更快。 处理9个请求,单个线程持续02min08s,同时3个线程同时工作,时间减少到01min37s,但它不使用100%CPU,只有大约50%。

我怎么能让我的程序使用完整的处理器function?

编辑应用程序不是IO或内存有限,它们一直处于合理的水平。

我认为它与’双核’事物有关。

每个请求都使用一个锁定的方法调用,但它确实很快,我不认为这是问题所在。

我的代码中代价更高的部分是通过COM调用dll(从所有线程调用相同的外部方法)。 这个dll也没有内存或IO限制,它是一个AI识别组件,我正在对薪水进行OCR识别,对请求进行薪水检查。

EDIT2

STA COM方法很可能是我的问题,我联系了组件所有者以解决这个问题。

您的应用程序中是否存在重要锁定? 如果线程相互等待很多,那很容易解释它。

除此之外(以及给出的其他答案),真的很难猜到。 探查器是你的朋友……

编辑:好的,鉴于下面的评论,我想我们正在做点什么:

我的代码中代价更高的部分是通过COM调用dll(从所有线程调用相同的外部方法)。

COM方法是否在STA中运行? 如果是这样,它将只使用一个线程,序列化调用。 我强烈怀疑这是关键。 它类似于锁定该方法调用(不可否认,不完全相同)。

问题是COM对象。

大多数COM对象在“单线程单元”的上下文中运行。 (您可能不时在.NET应用程序的main方法上看到[STAThread]注释?)

实际上,这意味着对该对象的所有调度都由单个线程处理。 在问题上投入更多内核只会为您提供更多可以在.NET中等待或执行其他操作的资源。

您可能想看看Joe Duffy(微软的并行.NET主管)关于该主题的这篇文章。

http://www.bluebytesoftware.com/blog/PermaLink,guid,8c2fed10-75b2-416b-aabc-c18ce8fe2ed4.aspx

实际上,如果你必须针对像这样的单个COM对象做一些事情,那么你就会受到冲击,因为.NET只会在你的背后内部序列化访问模式。 如果您可以创建多个COM对象并使用它们,则可以解决该问题,因为可以从不同的STA线程创建和访问每个对象。 这将一直有效,直到你达到大约100个STA线程,然后事情会变得不稳定。 有关详细信息,请参阅文章。

处理器可能不再是完成流程的瓶颈。 瓶颈可能转移到磁盘访问,网络访问或内存访问。 您还可能遇到线程争用锁定的情况。

只有你确切地知道你的线程在做什么,所以你需要考虑到上面的内容。

这取决于你的程序做什么 – 你的并发请求所执行的工作可能是IO限制的 – 受到(例如)硬盘速度的限制 – 而不是CPU限制,当你看到你的CPU达到100%时。

在编辑之后,它听起来像COM STA对象可能是罪魁祸首。

是否所有线程都调用COM对象的同一个实例? 是否可以使您的工作线程成为STA线程,并在每个线程上创建一个单独的COM对象实例。 通过这种方式,可以避免STA瓶颈。

要判断COM coclass是否为STA:

class Test { static void Main() //This will be an MTA thread by default { var o = new COMObjectClass(); // Did a new thread pop into existence when that line was executed? // If so, .NET created an STA thread for it to live in. } } 

我想我有类似的问题。 我在c#中创建多个线程,通过COM接口运行c ++代码。 我的双核CPU从未达到100%。

看完这篇文章后,我几乎放弃了。 然后我尝试在我的线程上调用SetApartmentState(ApartmentState.STA)。

仅更改此值后,CPU最大化。

听起来您的应用程序的性能可能不受可用的CPU资源量的“约束”。 如果您正在通过网络处理请求,则cpu可能正在等待数据到达,或者网络设备要传输数据。 或者,如果您需要查找数据以满足请求,则cpu可能正在等待磁盘。

您确定您的任务需要密集的处理器活动吗? 有没有IO处理? 这可能是您50%负载的原因。

测试:尝试仅使用2个线程,并为每个Core设置每个线程的亲和力。 然后打开任务管理器并观察两个核心的负载。

这不是一个真正的答案,但你检查了perfmon以查看它正在使用的资源,并让你在代码上运行分析器,看看它花费的时间在哪里?

您如何确定IO或其他非CPU资源不是瓶颈?

你能简单介绍一下线程在做什么吗?

如果你的进程在cpu 0上运行并在那里产生线程,它将达到的最大值是50%。 查看是否在两个核心上或仅在一个核心上运行线程。 我冒昧地猜测你被孤立到一个核心,或者你的一个依赖资源被锁定在一个核心上。 如果它恰好达到50%,则单个核心很可能成为您的瓶颈。

所以你解决了使用单个COM对象的问题,现在有一个IO问题。

多个线程的运行时间增加可能是因为将随机IO混合在一起,这将减慢所有速度。

如果数据集适合RAM,请尝试查看是否可以将其预取到缓存中。 也许只是读取数据,或者可能将内存与命令一起映射以使其可用。

这就是为什么SQL数据库通常会对您不希望的查询进行索引扫描的顺序表扫描:按顺序读取所有数据的速度比以随机数据块读取它要快得多。

也许我误解了一些东西,但你说没有你的请求(每个都在一个单独的线程中)达到100%的CPU。

您使用什么操作系统?

我似乎模糊地回忆起在旧版本的Windows中(例如,早期的XP和2000s),CPU利用率被认为是总共两个处理器,因此单个线程无法使其超过50%,除非它是空闲进程..

还有一点需要注意,您是否尝试过不是从Visual Studio启动代码(无论发布/调试设置如何)?

问题是COM对象。 它是STA,我不能在同一进程上同时运行两个实例。 当我为COM类创建实例时,另一个实例变得无法使用。

我联系了组件开发人员,他们正在考虑他们能为我做些什么。

谢谢大家;)