Программа 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 раза медленнее!

HP DL120G7 E3-1220

~ 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

HP DL360p G8 2 * E5-2640

~ 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

Ответы на вопрос(1)

Ваш ответ на вопрос