简体   繁体   English

使用C#和APM的CPU使用率不是100%的原因是什么?

[英]What are the reasons why the CPU usage doesn’t go 100% with C# and APM?

I have an application which is CPU intensive. 我有一个CPU密集型的应用程序。 When the data is processed on a single thread, the CPU usage goes to 100% for many minutes. 在单个线程上处理数据时,CPU使用率会持续很长时间达到100%。 So the performance of the application appears to be bound by the CPU. 因此应用程序的性能似乎受到CPU的约束。 I have multithreaded the logic of the application, which result in an increase of the overall performance. 我已经多线程化了应用程序的逻辑,从而提高了整体性能。 However, the CPU usage hardly goes above 30%-50%. 但是,CPU使用率几乎不超过30%-50%。 I would expect the CPU (and the many cores) to go to 100% since I process many set of data at the same time. 我期望CPU(和许多核心)达到100%,因为我同时处理了许多数据集。

Below is a simplified example of the logic I use to start the threads. 下面是我用来启动线程的逻辑的简化示例。 When I run this example, the CPU goes to 100% (on an 8/16 cores machine). 当我运行这个例子时,CPU达到100%(在8/16核心机器上)。 However, my application which uses the same pattern doesn't. 但是,我使用相同模式的应用程序没有。

public class DataExecutionContext
{
    public int Counter { get; set; }

    // Arrays of data
}

static void Main(string[] args)
{
    // Load data from the database into the context
    var contexts = new List<DataExecutionContext>(100);
    for (int i = 0; i < 100; i++)
    {
        contexts.Add(new DataExecutionContext());
    }

    // Data loaded. Start to process.
    var latch = new CountdownEvent(contexts.Count);
    var processData = new Action<DataExecutionContext>(c =>
    {
        // The thread doesn't access data from a DB, file, 
        // network, etc. It reads and write data in RAM only 
        // (in its context).
        for (int i = 0; i < 100000000; i++)
            c.Counter++;
    });

    foreach (var context in contexts)
    {
        processData.BeginInvoke(context, new AsyncCallback(ar =>
        {
            latch.Signal();
        }), null);
    }

    latch.Wait();
}

I have reduced the number of locks to the strict minimum (only the latch is locking). 我已将锁的数量减少到严格的最小值(只有锁定器锁定)。 The best way I found was to create a context in which a thread can read/write in memory. 我发现的最好方法是创建一个线程可以在内存中读/写的上下文。 Contexts are not shared among other threads. 上下文不在其他线程之间共享。 The threads can't access the database, files or network. 线程无法访问数据库,文件或网络。 In other words, I profiled my application and I didn't find any bottleneck. 换句话说,我描述了我的应用程序,我没有发现任何瓶颈。

Why the CPU usage of my application doesn't go about 50%? 为什么我的应用程序的CPU使用率不会达到50%左右? Is it the pattern I use? 这是我使用的模式吗? Should I create my own thread instead of using the .Net thread pool? 我应该创建自己的线程而不是使用.Net线程池吗? Is there any gotchas? 有没有陷阱? Is there any tool that you could recommend me to find my issue? 有什么工具可以推荐我找到我的问题吗?

Thanks! 谢谢!

There are many things that could, potentially, cause this behavior. 有很多事情可能会导致这种行为。

First, what type of CPU do you have? 首先,你有什么类型的CPU? If you have an i7 or similar processor, the OS will see this as having 8 cores, when in reality, it has 4 cores with 2 hyperthreads/core. 如果您有i7或类似的处理器,操作系统会将其视为具有8个内核,而实际上,它有4个内核,具有2个超线程/核心。 For most operations, hyperthreading does not really provide the same scalability as a second core, even though the OS sees it this way. 对于大多数操作而言,即使操作系统以这种方式看到,超线程也不能提供与第二个核心相同的可扩展性。 I've had this cause my overall CPU usage to appear lower to the OS... 我有这个原因导致我的整体CPU使用率低于操作系统......

Second, it's possible you have some form of true sharing occurring. 其次,你可能会发生某种形式的真正共享。 You mention that you have locking - even if it's kept to a minimum, the locks may be preventing you from scheduling this effectively. 你提到你有锁定 - 即使它被保持在最低限度,锁可能会阻止你有效地安排这个。

Also, right now, you're scheduling all 100 work items, right up front. 此外,您现在正在安排所有100个工作项目。 The os is going to have to page in and out those 100 threads. 操作系统必须进出这100个线程。 You may want to restrict this to only allowing a certain number to process at a given time. 您可能希望将此限制为仅允许在给定时间处理特定数字。 This is much easier using the new Task Parallel Library (just use Parallel.ForEach with a ParallelOptions setup to have a maximum number of threads) - but can be done on your own. 使用新的任务并行库(使用Parallel.ForEach并使用ParallelOptions设置来获得最大线程数)会更容易 - 但可以自己完成。

Given that you're scheduling all 100 items to process simulataneously, the paging may be hampering the ability to get maximum throughput. 鉴于您要安排所有100个项目同时处理,分页可能会妨碍获得最大吞吐量的能力。

Also, if you're doing any other "more real" work - you may be getting false sharing issues, especially if you're working with arrays or collections that are shared (even if the elements you're process are not shared). 此外,如果您正在进行任何其他“更真实”的工作 - 您可能会遇到错误的共享问题,尤其是在您使用共享的数组或集合时(即使您处理的元素未共享)。

I'd recommend running this under the concurrency profiler in VS 2010 - it will give you a much clearer picture of what is happening. 我建议在VS 2010中的并发分析器下运行它 - 它会让你更清楚地了解正在发生的事情。

This is speculationg without seeing your application, but if your application is doing any processing dealing with files, databases, creating lots of objects(requesting memory), working with network devices, or hardware devices of any sort, then those factors might be limiting your application from reaching 100% cpu usage. 这是在没有看到您的应用程序的情况下推测,但如果您的应用程序正在处理文件,数据库,创建大量对象(请求内存),使用网络设备或任何类型的硬件设备,那么这些因素可能会限制您的应用程序达到100%cpu使用率。 This combined with thread switching might also be a factor. 这与线程切换相结合也可能是一个因素。

You say you are using the pattern of the example you gave, but you say the example reaches 100% utilization but your application does not. 你说你使用的是你给出的示例模式,但是你说这个例子达到了100%的利用率但你的应用却没有。 So there is some difference there, and you should try to describe in more detail what your application is doing. 因此存在一些差异,您应该尝试更详细地描述您的应用程序正在做什么。 50% utilization is not bad. 50%的利用率也不错。 Many applications run at 50% on hyper-threaded Intel CPUs and they still run fine. 许多应用程序在超线程Intel CPU上运行率为50%,并且运行良好。 If the application is not reaching 100% cpu utilization and you are still getting good performance, then I would say that is actually a good thing, because it means you have some head room since it is not CPU bound anymore. 如果应用程序没有达到100%的CPU利用率并且你仍然获得了良好的性能,那么我会说这实际上是一件好事,因为它意味着你有一些头部空间,因为它不再受CPU限制。 This means cases where other things might take up CPU time your application won't be affected as much. 这意味着其他事情可能占用CPU时间的情况下,您的应用程序不会受到太大影响。 If it were at 100% utilization then you would see the applications performance waver when other processes activily use the CPU. 如果它处于100%利用率,那么当其他进程激活使用CPU时,您会看到应用程序性能动摇。

如果要进行大量小内存分配 - 托管堆可以成为阻塞线程的共享资源,从而减慢进程并降低CPU使用率

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么C#中的多线程不能达到100%的CPU? - Why doesn't multithreading in C# reach 100% CPU? 使用Threads C#制作的聊天服务器的CPU使用率100% - Cpu usage 100% with a chat server made with Threads C# 100%CPU中的c#线程 - c# Thread in 100% CPU 在C#中闭包不是不可变的有什么充分的理由吗? - Are there any good reasons why closures aren't immutable in C#? SharePoint 2010中的PowerShell脚本可通过Management Shell运行,但不能通过C#代码运行。 可能是什么原因? - PowerShell script in SharePoint 2010 works via Management Shell but it doesn't work via C# code. What are possible reasons? 使用C#在Outlook中插入联系人时,CPU使用率达到100%? - CPU usage reachs 100% while inserting contacts in Outlook using C#? 2-3天后,C#中的TCP服务器导致100%CPU使用率 - TCP server in C# causing 100% CPU usage after 2-3 days 在C#程序中,我试图获取该应用程序的CPU使用率,但它始终显示为100 - In a C# Program, I am trying to get the CPU usage percentage of the application but it always shows 100 什么是动态语言,为什么C#不符合条件? - What is a dynamic language, and why doesn't C# qualify? 使用C#使用CPU的全部100%电源 - Use all 100% power of CPU with C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM