Работа с очень большими наборами данных и своевременная загрузка - PullRequest
9 голосов
/ 26 января 2011

У меня есть приложение .NET, написанное на C # (.NET 4.0).В этом приложении мы должны прочитать большой набор данных из файла и отобразить содержимое в виде сетки.Итак, для этого я поместил DataGridView на форму.Он имеет 3 столбца, все данные столбца поступают из файла.Первоначально в файле было около 600 000 записей, что соответствует 600 000 строк в DataGridView.

Я быстро обнаружил, что DataGridView разрушается с таким большим набором данных, поэтому мне пришлось переключиться в виртуальный режим.Для этого я сначала полностью прочитал файл в 3 различных массива (соответствующих 3 столбцам), а затем запускается событие CellValueNeeded, я предоставляю правильные значения из массивов.

Однако может быть огромный(ОГРОМНОЕ!) Количество записей в этом файле, как мы быстро выяснили.Когда размер записи очень большой, считывание всех данных в массив или список <> и т. Д. Представляется невозможным.Мы быстро сталкиваемся с ошибками выделения памяти.(Исключение из-за недостатка памяти).

Мы застряли там, но потом поняли, зачем сначала читать все данные в массивы, почему бы не прочитать файл по требованию, когда происходит событие CellValueNeeded?Вот что мы делаем сейчас: мы открываем файл, но ничего не читаем, и когда запускаются события CellValueNeeded, мы сначала ищем () правильную позицию в файле, а затем читаем соответствующие данные.

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

О, и, чтобы добавить к нашим проблемам, в виртуальном режимеDataGridView, когда мы устанавливаем для RowCount доступное количество строк в файле (скажем, 16.000.000), DataGridView требуется некоторое время, чтобы даже инициализировать себя.Любые комментарии к этой «проблеме» также приветствуются.

Спасибо

Ответы [ 5 ]

5 голосов
/ 26 января 2011

Если вы не можете разместить весь свой набор данных в памяти, вам нужна схема буферизации.Вместо того, чтобы читать только объем данных, необходимый для заполнения DataGridView в ответ на CellValueNeeded, ваше приложение должно предвидеть действия пользователя и читать вперед.Так, например, когда программа запускается впервые, она должна прочитать первые 10000 записей (или, может быть, только 1000 или, возможно, 100000 - что бы ни было разумно в вашем случае).Затем CellValueNeeded запросы могут быть немедленно заполнены из памяти.

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

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

16 миллионов записей не так уж много, чтобы хранить в памяти, если только записи не очень большие.Или если у вас мало памяти на вашем сервере.Конечно, 16 миллионов далеко не максимальный размер List<T>, если только T не является типом значения (структурой).Сколько гигабайт данных вы говорите здесь?

3 голосов
/ 27 января 2011

Хорошо, вот решение, которое, кажется, работает намного лучше:

Шаг 0: установите для dataGridView.RowCount низкое значение, скажем, 25 (или фактическое число, которое соответствует вашей форме / экрану)

Шаг 1. Отключите полосу прокрутки dataGridView.

Шаг 2. Добавьте собственную полосу прокрутки.

Шаг 3. В вашей подпрограмме CellValueNeeded ответьте на e.RowIndex + scrollBar.Value

Шаг 4. Что касается хранилища данных, я в настоящее время открываю поток, а в подпрограмме CellValueNeeded сначала выполняю Seek () и Read () требуемые данные.

С этими шагами я получаю очень разумную производительность при прокрутке dataGrid для очень больших файлов (проверено до 0,8 ГБ).

Итак, в заключение, похоже, что действительной причиной замедления был не тот факт, что мы сохранили Seek () ing и Read () ing, а сам фактический dataGridView.

1 голос
/ 31 января 2012

Поскольку .net находится поверх собственной операционной системы, загрузка во время выполнения и управление данными с диска в память требует другого подхода. Посмотрите, почему и как: http://www.codeproject.com/Articles/38069/Memory-Management-in-NET

1 голос
/ 26 января 2011

Управление строками и столбцами, которые можно свернуть, подвести итоги, использовать в многоколоночных вычислениях и т. Д., Представляет собой уникальный набор проблем; не совсем справедливо сравнивать проблему с теми, с которыми столкнется редактор. Сторонние элементы управления сеткой данных решают проблему отображения и манипулирования большими наборами данных на стороне клиента с VB6 дней. Это не тривиальная задача, чтобы получить действительно быструю производительность, используя либо наборы данных по требованию, либо автономные клиентские наборы данных garguantuan. Нагрузка по требованию может страдать от задержки на стороне сервера; манипулирование всем набором данных на клиенте может страдать от ограничений памяти и процессора. Некоторые сторонние элементы управления, которые поддерживают своевременную загрузку, предоставляют как клиентскую, так и серверную логику, в то время как другие пытаются решить проблему на 100% на стороне клиента.

0 голосов
/ 31 марта 2014

Для решения этой проблемы я бы предложил не загружать все данные сразу. Вместо этого загрузите данные в виде фрагментов и при необходимости отобразите наиболее релевантные данные. Я только что сделал быстрый тест и обнаружил, что установка свойства DataSource для DataGridView - это хороший подход, но при большом количестве строк это также требует времени. Поэтому используйте функцию Merge DataTable для загрузки данных в виде фрагментов и показа пользователю наиболее релевантных данных. Здесь Я продемонстрировал пример, который может вам помочь.

...