.Net 2.0 - Насколько эффективны общие списки?

Я создаю приложение, которое хранит множество пользовательских данных в памяти, и в основном хранит их в структурах List ‹T› (и немного Dictionary ‹T, T›, когда мне нужен поиск).

И мне интересно ...

Насколько эффективны списки? Сколько накладных расходов памяти я получу для каждого из них? (то есть пространство памяти в дополнение к тому, что будут занимать объекты, которые они содержат). Какую сумму штрафа я выплачиваю каждый раз, когда создаю новый объект?

Есть более эффективный способ?

Словари - это просто HashTables, верно? Или это менее эффективная структура данных?

Я хотел бы использовать массивы, но у меня типичная проблема с постоянным добавлением и удалением вещей из них, поэтому необходимость их увеличения / уменьшения была бы проблемой.

Есть идеи / предложения?


Изменить: я знаю свои основные структуры данных 101 и почему связанный список лучше для добавления / удаления, а HashTable лучше для произвольного доступа.

Меня больше всего беспокоит идионсинкразия .Net. Например, сколько памяти тратит каждая из этих структур. И время потрачено на их инициализацию / уничтожение.

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

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

И я также очень хотел бы сосредоточиться на использовании памяти, поскольку мое приложение чрезвычайно интенсивно использует память (например, memcached) ... Кто-нибудь знает, где я могу найти такую ​​информацию?


person Community    schedule 28.08.2008    source источник
comment
Почему вы восстанавливаете эту тему сейчас, спустя более двух лет после того, как вы ее впервые опубликовали? Обратите внимание: редактируя его, вы переносите его на первую страницу. Если вы не хотите, чтобы интерес к вашему вопросу возобновился, оставьте его как есть, с бородавками и всем остальным.   -  person Lasse V. Karlsen    schedule 03.10.2010


Ответы (10)


Возможно, вам стоит подумать об использовании какой-либо базы данных в памяти, если у вас есть столько данных, которые должны храниться в памяти,

person Vaibhav    schedule 28.08.2008
comment
О какой базе данных в памяти вы думаете? Наборы данных? Насколько я понимаю, они чертовски медленные ... Или вы думаете о какой-нибудь внепроцессной базе данных, например, о MySQL с таблицей в памяти? (или memcached?) - person Daniel Magliola; 29.08.2008
comment
Во-первых, если вы собираетесь прокомментировать ответ, используйте функцию добавления комментария. Во-вторых, я подозреваю, что он думает о чем-то вроде SQLite (sqlite.org). - person chyne; 03.06.2009

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

В противном случае они будут в основном такими же быстрыми, как массив.

person Nick    schedule 28.08.2008

List использует массив внутри, а Dictionary использует хеш-таблицу.

Они быстрее, чем старые неуниверсальные классы ArrayList и HashTable, потому что у вас нет затрат на преобразование всего в объект / из объекта (упаковка, распаковка и проверка типов), а также потому, что MS оптимизировала их лучше, чем старые классы.

person Nir    schedule 28.08.2008

Если вам нужна эффективность при вставке или удалении случайных мест в списке, существует структура данных LinkedList - Статья в MSDN содержит подробности. Очевидно, что произвольный доступ к связанному списку неэффективен.

person ljs    schedule 28.08.2008
comment
Я всегда добавляю в конец списка. Много раз я удалял из середины некоторых из самых больших списков. Чем отличаются связанные списки, помимо времени вставки / удаления, от обычных списков? (память, время прохождения и т. д.) - person Daniel Magliola; 29.08.2008

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

См. Это в Википедии: Связанные списки против массивов

person Jesse Dearing    schedule 28.08.2008
comment
Но разве LinkedList .Net не оборачивает каждый из моих объектов в новый объект? Разве это не приведет к потере много памяти? Меня действительно беспокоят потребности этого приложения в памяти, я бы хотел, чтобы их объем был как можно меньше. - person Daniel Magliola; 29.08.2008
comment
@Daniel: Будучи связанными списками, они эффективны при случайных вставках и удалениях, либо отсутствуют, либо неэффективны при произвольном доступе (я не играл с ними, поэтому не знаю, какие), и их можно перемещать от начала до конца. Если вам нужен произвольный доступ, я думаю, что List ‹T› или Dictionary ‹T, T› подойдут, в зависимости от того, хотите ли вы получить доступ к участникам по индексу или по значению. - person ljs; 29.08.2008
comment
Он действительно оборачивает объект в объект LinkedListNode, но этот объект состоит из 4 свойств, но 3 из них являются просто ссылками на другие объекты, занимающие очень небольшой объем памяти, а 4-е - ваш фактический объект. Вы всегда можете написать свой собственный связанный список, чтобы уменьшить накладные расходы, добавляемые типом .NET. Изначально я сказал использовать структуру, но это, вероятно, также работает в C #. - person Jesse Dearing; 29.08.2008

Если вы действительно хотите увидеть все кровавые подробности того, как реализованы List ‹> и Dictionary‹,>, используйте замечательно полезный Рефлектор .NET.

См. Также документацию по отличной библиотеке общих коллекций C5, в которой есть очень хорошие реализации количество типов коллекций, отсутствующих в BCL.

person McKenzieG1    schedule 31.08.2008

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

Ключ состоит в том, чтобы использовать FILE_FLAG_NO_BUFFERING и всегда читать / записывать данные размером ровно в один сектор.

person Nick    schedule 28.08.2008
comment
К сожалению, мне все-таки нужно держать все в памяти, я думаю ... Большую часть наверняка ... Но ваш ответ открыл мне много интересных идей. Может быть, мне удастся сохранить на диске кое-что из того, что я использую реже. Есть идеи, как разрешить Windows PAGE автоматически переходить в HD? Например, могу ли я хранить свои менее часто используемые данные в отдельном процессе и каким-то образом дать этому другому процессу меньший приоритет памяти, чем основному? Таким образом, когда системе не хватает памяти, она может сначала публиковать ТАКИЕ менее приоритетные вещи, а мои самые важные вещи хранить в ОЗУ? Я мечтаю? - person Daniel Magliola; 29.08.2008
comment
Вы можете повысить вероятность того, что ваши менее часто используемые данные будут выгружаться на страницы, если будете использовать их реже. - person Jon Hanna; 11.11.2010

Я думаю, что двухпроцессный подход был бы излишним; плюс межпроцессное взаимодействие, вероятно, будет иметь некоторую медлительность (хотя я никогда не пробовал такую ​​вещь, поэтому примите мое мнение об этом как о крупице скепсиса). Я работаю над приложением, управляемым данными, где каждая единица данных крошечная, но в любой момент времени у нас может быть до миллиарда единиц данных. В основном мы используем следующие методы:

  • Все находится на диске, несмотря ни на что
  • Данные блокируются на «куски»; каждый чанк знает, когда к нему в последний раз обращались
  • Чанки перетаскиваются с диска в память, когда они нужны
  • Поток с низким приоритетом отслеживает использование памяти и удаляет наименее недавно использованные данные.

Другими словами, это домашняя схема кеширования. Преимущество заключается в том, что вы можете с очень высокой точностью контролировать, какие данные находятся в памяти, чего нельзя сделать, если вы полагаетесь на схему подкачки ОС. Если какая-то часто используемая переменная оказывается смешанной с вашими данными на странице, эта страница будет подвергаться многократному обращению и не позволит ей попасть на диск. Если вы спроектируете в своем приложении приспособление, при котором одни запросы данных займут больше времени, чем другие, тогда это будет работать очень хорошо. В частности, если вы заранее знаете, какие куски вам понадобятся (мы не знаем).

Имейте в виду, что все в приложении .NET должно умещаться в пределах 2 ГБ памяти, и из-за того, как работает сборщик мусора, и накладных расходов вашего приложения, у вас, вероятно, на самом деле немного меньше, чем нужно для работы.

Чтобы точно узнать, как выглядит ваша куча и кто ее выделяет, используйте профилировщик CLR: http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang >

person Nick    schedule 28.08.2008
comment
Ограничены ли процессы .Net 2 ГБ в Windows x64? Эээ ... Ой ... Я рассчитывала на противоположное: -S - person Daniel Magliola; 29.08.2008
comment
Я думаю, что x64 позволит вам адресовать 4 ГБ, я не учел. Однако я бы не стал рассчитывать на то, что полностью избегу OutOfMemory до этого предела, поскольку GC не будет идеально упаковывать ваши объекты в это пространство (фрагментация кучи). - person Nick; 29.08.2008
comment
Отвечу на свой вопрос: нет, это не так. - person Daniel Magliola; 03.06.2009

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

person pupeno    schedule 03.06.2009

Список .Net не использует связанный список. Это массив, по умолчанию он начинается с 4 позиций, и я думаю, что он удваивается в размере по мере добавления элементов. Таким образом, производительность может немного отличаться в зависимости от того, как вы ее используете.


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

person Dan Blair    schedule 28.08.2008
comment
Хорошая идея о профайлере. Могу ли я запустить это против живого процесса на сервере, не устанавливая в него всю VS 2008? Может быть, я могу вставить туда небольшую программу, которая даст мне журнал? Какие-нибудь инструменты, похожие на профилировщик, которые позволят мне увидеть, на что используется моя память? (например, сколько экземпляров каждого класса или сколько байтов в экземплярах каждого класса) - person Daniel Magliola; 29.08.2008
comment
Относительно инструментов: см. stackoverflow.com/questions/134086. Лично я добился успеха с WinDbg + SOS. - person Constantin; 27.09.2008