размер элемента влияет на производительность коллекции C #? - PullRequest
0 голосов
/ 03 октября 2018

Учитывая задачу улучшить производительность фрагмента кода, я столкнулся со следующим явлением.У меня есть большая коллекция ссылочных типов в общей очереди, и я удаляю и обрабатываю элемент один за другим, а затем добавляю их в другую общую коллекцию.

Кажется, чем больше элементы, тем больше времени у неготребуется, чтобы добавить элемент в коллекцию.

Пытаясь сузить проблему до соответствующей части кода, я написал тест (исключая обработку элементов, просто делая вставку):

    class Small 
    {
        public Small()
        {
            this.s001 = "001";
            this.s002 = "002";
        }
        string s001;
        string s002;
    }


    class Large
    {
        public Large()
        {
            this.s001 = "001";
            this.s002 = "002";
            ...
            this.s050 = "050";

        }
        string s001;
        string s002;
        ...
        string s050;
    }

    static void Main(string[] args)
    {
        const int N = 1000000;
        var storage = new List<object>(N);
        for (int i = 0; i < N; ++i)
        {
            //storage.Add(new Small());
            storage.Add(new Large());
        }

        List<object> outCollection = new List<object>();
        Stopwatch sw = new Stopwatch();

        sw.Start();
        for (int i = N-1; i > 0; --i)
        {          
            outCollection.Add(storage[i];);
        }
        sw.Stop();

        Console.WriteLine(sw.ElapsedMilliseconds);
    }

НаДля тестовой машины, использующей класс Small, для ее запуска требуется около 25-30 мс, а для Large - 40-45 мс.Я знаю, что время от времени должна увеличиваться коллекция outCollection, чтобы иметь возможность хранить все элементы, поэтому существует некоторое динамическое распределение памяти.Но с учетом начального размера коллекции разница становится еще более очевидной: 11–12 мс для объектов Small и 35–38 мс для объектов Large.

Я несколько удивлен, поскольку это ссылочные типы, поэтому я ожидалколлекции работают только со ссылками на экземпляры Small / Large.Я прочитал соответствующую статью Эрика Липперта и знаю, что ссылки не должны рассматриваться как указатели.В то же время, AFAIK в настоящее время они реализованы в виде указателей, и их размер и производительность коллекции должны быть независимы от размера элемента.

Я решил задать здесь вопрос, надеясь, что кто-то сможет объяснить или помочь мнечтобы понять, что здесь происходит.Помимо повышения производительности, мне действительно любопытно, что происходит за кулисами.

Обновление: профилирование данных с использованием диагностических инструментов мне не сильно помогло, хотя я должен признать, что я не эксперт, использующийпрофилировщик.Позже сегодня я соберу больше данных, чтобы выяснить, где находится узкое место.

Конечно, давление на ГХ довольно высокое, особенно в случаях Large.Но как только экземпляры созданы и сохранены в коллекции storage, и программа входит в цикл, коллекция больше не запускается, и использование памяти существенно не увеличилось (outCollction уже предварительно выделено).

Большая часть процессорного времени, конечно, тратится на выделение памяти (JIT_New), около 62%, и единственной другой важной записью является Имя функции.List`1 [System .__ Canon] .Добавить около 7%.

Для 1 миллиона элементов предварительно выделенный размер outCollection составляет 8 миллионов байтов (аналогично размеру storage);можно заподозрить, что в коллекциях хранятся 64-битные адреса.

Возможно, я не использую инструменты должным образом или не имею опыта правильно интерпретировать результаты, но профилировщик не помог мне получитьближе к делу.Если цикл не запускает коллекции и копирует только указатели между 2 предварительно выделенными коллекциями, как может размер элемента вызывать какие-либо различия?Предполагается, что соотношение попаданий / промахов кэша в обоих случаях будет более или менее одинаковым, поскольку в обоих случаях цикл представляет собой итерацию по списку «адресов».

Спасибо за всю помощь, покасоберет больше данных и разместит здесь обновление, если что-нибудь найдет.

1 Ответ

0 голосов
/ 03 октября 2018

I подозреваю , что по крайней мере одно действие в приведенном выше (может быть, некоторые проверки типов) потребует отмены ссылки.Тогда тот факт, что многие Small s, вероятно, располагаются близко друг к другу в куче, и, таким образом, совместное использование строк кэша может составлять некоторое количество различий (конечно, гораздо больше из них могут совместно использовать одну строку кэша, чем Large s).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...