У меня есть приложение, которое является интенсивным ЦП. Когда данные обрабатываются на единственном потоке, использование ЦП переходит к 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? Есть ли какие-либо глюки? Есть ли какой-либо инструмент, что Вы могли рекомендовать мне найти свою проблему?
Спасибо!
Есть много вещей, которые потенциально могут вызвать такое поведение.
Во-первых, какой у вас тип процессора? Если у вас i7 или аналогичный процессор, ОС будет воспринимать его как имеющий 8 ядер, в то время как в действительности он имеет 4 ядра с 2 гиперпотоками на ядро. Для большинства операций гиперпоточность не обеспечивает такой же масштабируемости, как второе ядро, хотя ОС видит это именно так. У меня бывало так, что общее использование процессора казалось ОС более низким...
Во-вторых, возможно, у вас есть какая-то форма истинного разделения. Вы упомянули, что у вас есть блокировка - даже если она сведена к минимуму, блокировки могут мешать эффективному планированию.
Кроме того, сейчас вы планируете все 100 рабочих элементов, прямо перед этим. Операционной системе придется входить и выходить из этих 100 потоков. Возможно, вы захотите ограничить это, позволив обрабатывать только определенное количество потоков в определенное время. Это гораздо проще сделать с помощью новой библиотеки Task Parallel (просто используйте Parallel.ForEach с настройкой ParallelOptions для максимального числа потоков) - но это можно сделать и самостоятельно.
Учитывая, что вы планируете одновременную обработку всех 100 элементов, подкачка может препятствовать достижению максимальной пропускной способности.
Также, если вы выполняете любую другую "более реальную" работу - вы можете получить ложные проблемы с общим доступом, особенно если вы работаете с массивами или коллекциями, которые являются общими (даже если элементы, которые вы обрабатываете, не являются общими).
Я бы рекомендовал запустить это под профилировщиком параллелизма в VS 2010 - это даст вам гораздо более четкую картину происходящего.
Это спекуляция без просмотра вашего приложения, но если ваше приложение выполняет какую-либо обработку файлов, баз данных, создает множество объектов (запрашивает память), работает с сетевыми устройствами или аппаратными устройствами любого типа, то эти факторы могут ограничивать ваше приложение до 100% использования процессора. Это в сочетании с переключением потоков также может быть фактором.
Вы говорите, что используете шаблон из приведенного вами примера, но вы говорите, что пример достигает 100% использования, а ваше приложение этого не делает. Так что здесь есть некоторая разница, и вы должны попытаться более подробно описать, что делает ваше приложение. 50% загрузка - это неплохо. Многие приложения работают на 50% на гиперпоточных процессорах Intel и по-прежнему работают нормально. Если приложение не достигает 100% использования процессора, а вы по-прежнему получаете хорошую производительность, я бы сказал, что это на самом деле хорошо, потому что это означает, что у вас есть запас, поскольку он больше не привязан к процессору. Это означает, что случаи, когда другие вещи могут занимать процессорное время, не будут затронуты так сильно. Если бы он был загружен на 100%, вы бы увидели колебания производительности приложений, когда другие процессы активно используют ЦП.
Если вы делаете много небольших выделений памяти - управляемая куча может стать общим ресурсом, который блокирует потоков и замедляет процесс и, следовательно, использование ЦП