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

Mar*_*tin 13 .net c# multithreading asynchronous

我有一个CPU密集型的应用程序.在单个线程上处理数据时,CPU使用率会持续很长时间达到100%.因此应用程序的性能似乎受到CPU的约束.我已经多线程化了应用程序的逻辑,从而提高了整体性能.但是,CPU使用率几乎不超过30%-50%.我期望CPU(和许多核心)达到100%,因为我同时处理了许多数据集.

下面是我用来启动线程的逻辑的简化示例.当我运行这个例子时,CPU达到100%(在8/16核心机器上).但是,我使用相同模式的应用程序没有.

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();
}
Run Code Online (Sandbox Code Playgroud)

我已将锁的数量减少到严格的最小值(只有锁定器锁定).我发现的最好方法是创建一个线程可以在内存中读/写的上下文.上下文不在其他线程之间共享.线程无法访问数据库,文件或网络.换句话说,我描述了我的应用程序,我没有发现任何瓶颈.

为什么我的应用程序的CPU使用率不会达到50%左右?这是我使用的模式吗?我应该创建自己的线程而不是使用.Net线程池吗?有没有陷阱?有什么工具可以推荐我找到我的问题吗?

谢谢!

Ree*_*sey 6

有很多事情可能会导致这种行为.

首先,你有什么类型的CPU?如果您有一个i7或类似的处理器,操作系统会将其视为具有8个内核,而实际上,它有4个内核和2个超线程/核心.对于大多数操作而言,即使操作系统以这种方式看待,超线程也不能提供与第二个核心相同的可扩展性.我有这个原因导致我的整体CPU使用率低于操作系统......

其次,你可能会发生某种形式的真正共享.你提到你有锁定 - 即使它被保持在最低限度,锁可能会阻止你有效地安排这个.

此外,您现在正在安排所有100个工作项目.操作系统必须进出这100个线程.您可能希望将此限制为仅允许在给定时间处理特定数字.使用新的任务并行库(使用Parallel.ForEach并使用ParallelOptions设置来获得最大线程数)会更容易 - 但可以自己完成.

鉴于您要安排所有100个项目同时处理,分页可能会妨碍获得最大吞吐量的能力.

此外,如果您正在进行任何其他"更真实"的工作 - 您可能会遇到错误的共享问题,尤其是在您使用共享的数组或集合时(即使您处理的元素未共享).

我建议在VS 2010中的并发分析器下运行它 - 它会让你更清楚地了解正在发生的事情.