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

У меня есть приложение, которое является интенсивным ЦП. Когда данные обрабатываются на единственном потоке, использование ЦП переходит к 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? Есть ли какие-либо глюки? Есть ли какой-либо инструмент, что Вы могли рекомендовать мне найти свою проблему?

Спасибо!

13
задан tomix86 29 December 2017 в 13:22
поделиться

3 ответа

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

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

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

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

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

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

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

6
ответ дан 2 December 2019 в 01:41
поделиться

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

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

2
ответ дан 2 December 2019 в 01:41
поделиться

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

0
ответ дан 2 December 2019 в 01:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: