По каким причинам загрузка ЦП не идет на 100% с C # и APM? - PullRequest
13 голосов
/ 23 февраля 2010

У меня есть приложение, которое интенсивно использует процессор. Когда данные обрабатываются в одном потоке, загрузка процессора увеличивается до 100% в течение многих минут. Таким образом, производительность приложения зависит от процессора. Я использовал многопоточную логику приложения, что приводит к увеличению общей производительности. Тем не менее, загрузка процессора едва ли превышает 30% -50%. Я ожидаю, что процессор (и многие ядра) перейдут на 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? Есть ли какие-нибудь ошибки? Есть ли какой-нибудь инструмент, который вы могли бы порекомендовать мне найти мою проблему?

Спасибо!

Ответы [ 3 ]

6 голосов
/ 23 февраля 2010

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

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

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

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

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

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

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

2 голосов
/ 23 февраля 2010

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

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

0 голосов
/ 13 мая 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...