Каковы причины, по которым использование ЦП не идет на 100% с С# и APM?

У меня есть приложение с интенсивным процессором. Когда данные обрабатываются в одном потоке, использование ЦП длится 100% в течение многих минут. Таким образом, производительность приложения, по-видимому, связана с процессором. Я многократно продиктовал логику приложения, что привело к увеличению общей производительности. Однако использование ЦП почти не превышает 30% -50%. Я бы ожидал, что CPU (и многие ядра) перейдут на 100%, поскольку я обрабатываю много данных одновременно.

Ниже приведен упрощенный пример логики, которую я использую для запуска потоков. Когда я запускаю этот пример, процессор переходит на 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();
}

Я сократил количество блокировок до строгого минимума (только защелка блокируется). Лучший способ, который я нашел, - создать контекст, в котором поток может читать/записывать в память. Контексты не распространяются среди других потоков. Нитки не могут получить доступ к базе данных, файлам или сети. Другими словами, я профилировал свое приложение, и я не нашел узкого места.

Почему использование процессора моим приложением не превышает 50%? Я использую шаблон? Должен ли я создать свой собственный поток вместо использования пула потоков .Net? Есть ли какие-то ошибки? Есть ли какой-нибудь инструмент, который вы могли бы рекомендовать мне найти мою проблему?

Спасибо!

Ответы

Ответ 1

Есть много вещей, которые могли бы потенциально вызвать это поведение.

Во-первых, какой тип процессора у вас есть? Если у вас есть i7 или аналогичный процессор, ОС увидит, что это имеет 8 ядер, тогда как на самом деле он имеет 4 ядра с двумя гиперпотоками/ядром. Для большинства операций гиперпоточность на самом деле не обеспечивает такую ​​же масштабируемость, как второе ядро, хотя ОС видит это так. У меня было это, поэтому мое общее использование ЦП оказалось ниже для ОС...

Во-вторых, возможно, у вас есть какая-то форма настоящего обмена. Вы отмечаете, что у вас есть блокировка - даже если она сведена к минимуму, блокировки могут помешать вам эффективно планировать это.

Кроме того, прямо сейчас вы планируете все 100 рабочих элементов, прямо вверх. В os придется вставлять и выводить эти 100 потоков. Вы можете ограничить это тем, что только определенное число обрабатывается в данный момент времени. Это намного проще с использованием новой параллельной библиотеки задач (просто используйте Parallel.ForEach с настройкой ParallelOptions, чтобы иметь максимальное количество потоков), но можно сделать самостоятельно.

Учитывая, что вы планируете все 100 элементов обрабатывать одновременно, пейджинг может затруднять возможность максимальной пропускной способности.

Кроме того, если вы выполняете какую-либо другую "более реальную" работу, вы можете получать ложные проблемы с распространением, особенно если вы работаете с массивами или коллекциями, которые являются общими (даже если элементы, которые вы выполняете, не являются общий).

Я бы рекомендовал запустить его под профилем concurrency в VS 2010 - он даст вам более четкое представление о том, что происходит.

Ответ 2

Это speculationg, не видя вашего приложения, но если ваше приложение обрабатывает файлы, базы данных, создает множество объектов (запрашивая память), работая с сетевыми устройствами или аппаратными устройствами любого типа, тогда эти факторы могут ограничьте применение приложения до 100% -ного использования процессора. Это в сочетании с переключением потоков также может быть фактором.

Вы говорите, что используете образец примера, который вы указали, но вы говорите, что пример достигает 100% использования, но ваше приложение этого не делает. Таким образом, есть какая-то разница, и вы должны попытаться более подробно описать, что делает ваше приложение. 50% использования не плохо. Многие приложения работают на 50% на процессорах Intel с высоким потоком, и они все еще работают нормально. Если приложение не достигает 100% -ного использования процессора, и вы по-прежнему получаете хорошую производительность, я бы сказал, что на самом деле это хорошо, потому что это означает, что у вас есть начальная комната, поскольку она больше не связана с ЦП. Это означает случаи, когда другие вещи могут занять процессорное время, на которое ваше приложение не будет затронуто. Если бы это было при 100% -ном использовании, вы бы увидели, что производительность приложений колеблется, когда другие процессы активно используют CPU.

Ответ 3

Если вы делаете много небольших распределений памяти - управляемая куча может стать общим ресурсом, который блокирует потоки и замедляет процесс и, следовательно, использование ЦП