为什么不';C#中的t多线程达到100%的CPU

本文关键字:100% CPU 多线程 中的 为什么不 | 更新日期: 2023-09-27 17:48:48

我正在开发一个程序,该程序处理许多请求,其中没有一个请求达到CPU的50%以上(目前我正在开发双核)。所以我为每个请求创建了一个线程,整个过程更快。处理9个请求时,单个线程持续02min08s,而3个线程同时工作时,时间减少到01min37s,但它并没有使用100%的CPU,只有50%左右。

如何允许我的程序使用全处理器功能?

编辑应用程序不受IO或内存限制,它们始终处于合理的水平。

我认为这与"双核"有关。

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

我的代码中cpu成本较高的部分是通过COM调用dll(从所有线程调用相同的外部方法)。这个dll也没有内存或IO限制,它是一个AI识别组件,我正在对工资支票进行OCR识别,这是一个请求的工资支票。

EDIT2

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

为什么不';C#中的t多线程达到100%的CPU

您的应用程序中是否有显著的锁定?如果线程彼此等待的时间很长,这很容易解释

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

编辑:好吧,根据下面的评论,我认为我们已经找到了一些东西:

我的代码中cpu成本较高的部分通过COM调用dll(相同外部方法是从所有螺纹)。

COM方法是否在STA中运行?如果是这样,它将只使用一个线程,序列化调用。我强烈怀疑这就是它的关键。这类似于在方法调用周围有一个锁(诚然,不太一样)。

问题出在COM对象上。

大多数COM对象都在"单线程单元"的上下文中运行。(您可能不时在.NET应用程序的主方法上看到[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组件类是否为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和2000年代),CPU利用率是从总共两个处理器中考虑的,所以一个线程不可能超过50%,除非它是空闲进程。。

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

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

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

谢谢大家;)