При профилировании приложения (с помощью dotTrace) я заметил очень странную вещь. Я использовал измерение «времени стены», которое в теории должно означать, что все потоки будут работать в течение одинакового времени.
Но это было не так: некоторые темы (на самом деле те, которые меня больше всего интересовали) отображали общее время примерно в 2 раза меньше, чем другие. Например, профилирование выполняется в течение 230 секунд, большинство потоков сообщают о 230 секундах, проведенных в потоке, но 5 потоков показывают только 100-110 секунд. Это не потоки потоков, и они определенно были созданы и запущены до начала профилирования.
Что здесь происходит?
Обновление Я добавлю больше информации, которая может иметь или не иметь отношение. Рассматриваемое приложение (это игровой сервер) имеет около 20-30 постоянно работающих потоков. Большинство потоков следуют простому шаблону: они проверяют входящую очередь на работу и выполняют работу, если она есть. Код для функции func выглядит примерно так:
while(true){
if(TryDequeueWork()){ // if queue is not empty
DoWork(); // do whatever is was on top
}else{
m_WaitHandle.WaitOne(MaxTimeout); // m_WaitHandle gets signaled when work is added to queue
}
}
Потоки, которые отображают странные времена, похожи на это, за исключением того, что они обслуживают несколько очередей, например:
while(true){
bool hasAnyWork=false;
foreach(var queue in m_Queues){
if(queue.TryDequeueWork()){
hasAnyWork=true;
DoWork();
}
}
if(!hasAnyWork){
m_WaitHandle.WaitOne(MaxTimeout);
}
}
Странные потоки не выполняют никаких операций ввода-вывода, кроме, возможно, регистрации. Другие, не странные темы, тоже ведите логи. Время, потраченное на ожидание WaitHandle, указывается в профилировщике; на самом деле, некоторые не странные потоки тратят почти все свое время на ожидание (так как у них никогда нет работы).
Приложение работало на 8-ядерной виртуальной машине (хостинг VPS). Я не знаю, какие физические процессоры там используются.