Программа Threadpool работает намного медленнее на гораздо более быстром сервере
upd Теперь я думаю, что корень моей проблемы не в «многопоточности», потому что я наблюдаю замедление в любой точке моей программы. Я думаю, что при использовании двух процессоров моя программа выполняется медленнее, вероятно, потому что два процессора должны "общаться" между друг другом. Мне нужно сделать несколько тестов. Я постараюсь отключить один из процессоров и посмотрю, что произойдет.
====================================
Я не уверен, что это вопрос C #, возможно, это больше касается аппаратного обеспечения, но я думаю, что C # будет наиболее подходящим.
Я использовал дешевый сервер DL120 и решил перейти на гораздо более дорогой сервер DL360p с двумя процессорами. Неожиданно моя программа на C # работает примерно в 2 раза медленнее на новом сервере, который должен быть в несколько раз быстрее.
Я обработалБЫСТРО данные для около 60 инструментов. Я создал отдельную задачу для каждого инструмента следующим образом:
BlockingCollection<OrderUpdate> updatesQuery;
if (instrument2OrderUpdates.ContainsKey(instrument))
{
updatesQuery = instrument2OrderUpdates[instrument];
} else
{
updatesQuery = new BlockingCollection<OrderUpdate>();
instrument2OrderUpdates[instrument] = updatesQuery;
ScheduleFastOrdersProcessing(updatesQuery);
}
orderUpdate.Checkpoint("updatesQuery.Add");
updatesQuery.Add(orderUpdate);
}
private void ScheduleFastOrdersProcessing(BlockingCollection<OrderUpdate> updatesQuery)
{
Task.Factory.StartNew(() =>
{
Instrument instrument = null;
OrderBook orderBook = null;
int lastRptSeqNum = -1;
while (!updatesQuery.IsCompleted)
{
OrderUpdate orderUpdate;
try
{
orderUpdate = updatesQuery.Take();
} catch(InvalidOperationException e)
{
Log.Push(LogItemType.Error, e.Message);
continue;
}
orderUpdate.Checkpoint("received from updatesQuery.Take()");
......................
...................... // long not interesting processing code
}, TaskCreationOptions.LongRunning);
Поскольку у меня есть около 60 задач, которые могут выполняться параллельно, я ожидаю, что 2 * E5-2640 (24 виртуальных потока, 12 реальных потоков) должны работать намного быстрее, чем 1 * E3-1220 (4 реальных потока). Кажется, что с помощью DL360p я нашел 95 потоков в диспетчере задач. Использование DL120 у меня только 55 потоков.
Но время выполнения на DL120G7 в 2 (!!) раза быстрее! E3-1220 имеет немного лучшую тактовую частоту, чем E5-2640 (3,1 ГГц против 2,5 ГГц), однако я все еще ожидаю, что мой код должен работать быстрее на 2 * E5-2640, потому что он может быть параллелизован намного лучше, и я абсолютно не ожидаю что это работает в 2 раза медленнее!
~ 50 потоков в диспетчере задач лучше всего = в среднем ~ 80 микросекунд
calling market.UpdateFastOrder = 23 updatesQuery.Add = 25 received from updatesQuery.Take() = 67 in orderbook = 80
calling market.UpdateFastOrder = 30 updatesQuery.Add = 32 received from updatesQuery.Take() = 64 in orderbook = 73
calling market.UpdateFastOrder = 31 updatesQuery.Add = 32 received from updatesQuery.Take() = 195 in orderbook = 204
calling market.UpdateFastOrder = 31 updatesQuery.Add = 32 received from updatesQuery.Take() = 74 in orderbook = 86
calling market.UpdateFastOrder = 18 updatesQuery.Add = 21 received from updatesQuery.Take() = 65 in orderbook = 78
calling market.UpdateFastOrder = 29 updatesQuery.Add = 32 received from updatesQuery.Take() = 76 in orderbook = 88
calling market.UpdateFastOrder = 30 updatesQuery.Add = 32 received from updatesQuery.Take() = 80 in orderbook = 92
calling market.UpdateFastOrder = 20 updatesQuery.Add = 21 received from updatesQuery.Take() = 65 in orderbook = 78
calling market.UpdateFastOrder = 21 updatesQuery.Add = 24 received from updatesQuery.Take() = 68 in orderbook = 81
calling market.UpdateFastOrder = 12 updatesQuery.Add = 13 received from updatesQuery.Take() = 58 in orderbook = 72
calling market.UpdateFastOrder = 22 updatesQuery.Add = 23 received from updatesQuery.Take() = 51 in orderbook = 59
calling market.UpdateFastOrder = 16 updatesQuery.Add = 16 received from updatesQuery.Take() = 20 in orderbook = 24
calling market.UpdateFastOrder = 28 updatesQuery.Add = 31 received from updatesQuery.Take() = 82 in orderbook = 94
calling market.UpdateFastOrder = 18 updatesQuery.Add = 21 received from updatesQuery.Take() = 65 in orderbook = 77
calling market.UpdateFastOrder = 29 updatesQuery.Add = 29 received from updatesQuery.Take() = 259 in orderbook = 264
calling market.UpdateFastOrder = 49 updatesQuery.Add = 52 received from updatesQuery.Take() = 99 in orderbook = 113
calling market.UpdateFastOrder = 22 updatesQuery.Add = 23 received from updatesQuery.Take() = 50 in orderbook = 60
calling market.UpdateFastOrder = 29 updatesQuery.Add = 32 received from updatesQuery.Take() = 76 in orderbook = 88
calling market.UpdateFastOrder = 16 updatesQuery.Add = 19 received from updatesQuery.Take() = 63 in orderbook = 75
calling market.UpdateFastOrder = 27 updatesQuery.Add = 27 received from updatesQuery.Take() = 226 in orderbook = 231
calling market.UpdateFastOrder = 15 updatesQuery.Add = 16 received from updatesQuery.Take() = 35 in orderbook = 42
calling market.UpdateFastOrder = 18 updatesQuery.Add = 21 received from updatesQuery.Take() = 66 in orderbook = 78
~ 95 потоков в диспетчере задач; лучший = 40 в среднем ~ 150 микросекунд
calling market.UpdateFastOrder = 62 updatesQuery.Add = 64 received from updatesQuery.Take() = 144 in orderbook = 205
calling market.UpdateFastOrder = 27 updatesQuery.Add = 32 received from updatesQuery.Take() = 101 in orderbook = 154
calling market.UpdateFastOrder = 45 updatesQuery.Add = 50 received from updatesQuery.Take() = 124 in orderbook = 187
calling market.UpdateFastOrder = 46 updatesQuery.Add = 51 received from updatesQuery.Take() = 127 in orderbook = 162
calling market.UpdateFastOrder = 63 updatesQuery.Add = 68 received from updatesQuery.Take() = 137 in orderbook = 174
calling market.UpdateFastOrder = 53 updatesQuery.Add = 55 received from updatesQuery.Take() = 133 in orderbook = 171
calling market.UpdateFastOrder = 44 updatesQuery.Add = 46 received from updatesQuery.Take() = 131 in orderbook = 158
calling market.UpdateFastOrder = 37 updatesQuery.Add = 39 received from updatesQuery.Take() = 102 in orderbook = 140
calling market.UpdateFastOrder = 45 updatesQuery.Add = 50 received from updatesQuery.Take() = 115 in orderbook = 154
calling market.UpdateFastOrder = 50 updatesQuery.Add = 55 received from updatesQuery.Take() = 133 in orderbook = 160
calling market.UpdateFastOrder = 26 updatesQuery.Add = 50 received from updatesQuery.Take() = 99 in orderbook = 111
calling market.UpdateFastOrder = 14 updatesQuery.Add = 30 received from updatesQuery.Take() = 36 in orderbook = 40 <-- best one I can find among thousands
Можете ли вы понять, почему моя программа работает в 2 раза медленнее на сервере в несколько раз быстрее? Вероятно, я не должен создавать ~ 60 Task? Вероятно, я должен сказать .NET не использовать 95 потоков, а ограничить его 50 или даже 24? Вероятно, это проблема 2 процессоров против 1 конфигурации процессора? Возможно, просто отключение одного из процессоров на моем DL360P Gen8 значительно ускорит программу?
Added
calling market.UpdateFastOrder - orderUpdate object is created updatesQuery.Add - orderUpdate is put into BlockingCollection received from updatesQuery.Take() - orderUpdate ejected from BlockingCollection in orderbook - orderUpdated is parsed and applied to orderBook