ConcurrentQueue.Count чрезвычайно медленно в .NET Core - PullRequest
0 голосов
/ 17 мая 2018

Я использую ConcurrentQueue для постановки в очередь элементов из связанной задачи ввода-вывода и удаления их из другой для обработки.Я прекращаю добавлять элементы в очередь, когда она достигает определенного размера, чтобы обработка могла наверстать упущенное.Для этого я проверяю свойство ConcurrentQueue.Count.

Проблема в том, что свойство Count не работает так, как в Списке или других коллекциях.Это чрезвычайно медленно, и чем больше очередь, тем медленнее требуется чтение свойства Count.С 20 тыс. Элементов в ConcurrentQueue почти все процессорное время затрачивается на свойство Count.

Грубый пример:

        while (reader.Read())
        {
            if(Queue.Count >= MaxQueueSize)
            {
                //Wait
            }
            //Do Stuff
        }

При запуске профилировщика производительностивсе время тратится на System.Collections.Concurrent.CDSCollectionETWBCLProvicer.ctor().

Это, кажется, происходит только в .NET Core 2, это не происходит в .NET 4.6.2

Есть ли способ обойти этов .Net Core?

1 Ответ

0 голосов
/ 17 мая 2018

Поскольку исходный код обеих платформ доступен в настоящее время, можно взглянуть на исходный код для обеих Count версий.Для полной версии .NET здесь , а для .NET Core здесь .Вы можете видеть, что:

  1. Обе версии нетривиальны.Это не что-то вроде return _count.

  2. .NET Core версия более сложная и включает медленные пути, где вся очередь замораживается только для вычисления стабильного числа.

ИтакНе удивительно, что версия .NET Core, как правило, медленнее, но главное - оба они нетривиальны, и использование их в узком цикле не является хорошей идеей.В дополнение к этому - у вас есть состояние гонки, если вы проверите это Count, потому что оно может быть изменено другим потоком сразу после его проверки, поэтому в вашей версии не гарантируется, что в вашей версии будет меньше максимального количества.

Вместо этого используйте встроенные ограниченные по объему коллекции, такие как BlockingCollection:

var x = new BlockingCollection<string>(new ConcurrentQueue<string>(), MaxQueueSize);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...