#c# #binary #binaryfiles #large-data
#c# #двоичный #двоичные файлы #большие данные
Вопрос:
У меня есть большой файл размером примерно 400 ГБ. Генерируется ежедневно внешней закрытой системой. Это двоичный файл следующего формата:
byte[8]byte[4]byte[n]
Где n равно значению int32 байта[4].
В этом файле нет разделителей, и для чтения всего файла вы просто повторяете до EOF. С каждым «элементом», представленным как байт [8] байт [4] байт [n].
Файл выглядит следующим образом
byte[8]byte[4]byte[n]byte[8]byte[4]byte[n]...EOF
байт [8] — это 64-разрядное число, представляющее период времени, представленный тиками .NET. Мне нужно отсортировать этот файл, но, похоже, я не могу найти самый быстрый способ сделать это.
В настоящее время я загружаю галочки в структуру и начальную и конечную позиции byte [n] и читаю до конца файла. После этого я сортирую список в памяти по свойству Ticks, а затем открываю BinaryReader и ищу каждую позицию в порядке тиков, считываю значение byte [n] и записываю во внешний файл.
В конце процесса я получаю отсортированный двоичный файл, но это занимает ЦЕЛУЮ ВЕЧНОСТЬ. Я использую C # .NET и довольно мощный сервер, но, похоже, проблема с дисковым вводом-выводом.
Характеристики сервера:
- 2x 2,6 ГГц Intel Xeon (шестиядерный процессор с HT) (24 потока)
- 32 ГБ оперативной памяти
- 500 ГБ RAID 1 0
- 2 ТБ RAID 5
Я просмотрел весь Интернет и могу найти только примеры, когда огромный файл составляет 1 ГБ (заставляет меня хихикать).
У кого-нибудь есть какие-либо советы?
Комментарии:
1. Я не уверен, что понимаю, как вам удается читать один файл объемом 400 ГБ и записывать другой, отсортированный файл объемом 400 ГБ в системе с RAID-диском объемом всего 500 ГБ, но предложение Грега звучит неплохо, хотя я лично не делал этого с файлами такого размера.
2. Эй, у меня также есть RAID 5 объемом 2 ТБ.
Ответ №1:
Отличный способ ускорить такого рода доступ к файлам — это отобразить весь файл в адресное пространство и позволить ОС самостоятельно считывать любые биты из файла, которые ей нужны. Так что делайте то же самое, что и сейчас, за исключением чтения из памяти вместо использования BinaryReader
/seek/read .
У вас много оперативной памяти, так что это должно обеспечить довольно хорошую производительность (при условии, что вы используете 64-разрядную ОС).
Комментарии:
1. Спасибо за быстрый ответ! Сможет ли MemoryMappedFile обрабатывать файл объемом 400 ГБ? Нужно ли мне создавать разные типы средств доступа к представлению (произвольный доступ или последовательный)? Еще раз спасибо! 🙂
2. MemoryMappedFile должен иметь возможность обрабатывать весь файл за один раз. Я делал это с помощью Python на FreeBSD с файлом объемом 30 ГБ, но я полностью ожидаю, что это будет нормально работать в Windows с вашим размером файла. Я не уверен в разнице между средствами доступа, но любой из них, вероятно, будет работать. Вы будете читать файл один раз последовательно, затем после сортировки вы будете читать его в случайном порядке.
Ответ №2:
Используйте сортировку слиянием. Это онлайн и хорошо распараллеливается.
Ответ №3:
Если вы можете изучить Erlang или Go, они могут быть очень мощными и очень хорошо масштабируемыми, поскольку у вас есть 24 потока. Используйте асинхронный ввод-вывод. Сортировка слиянием. И поскольку у вас 32 ГБ оперативной памяти, попробуйте загрузить в ОЗУ столько, сколько сможете, и отсортировать его там, а затем записать обратно на диск.
Ответ №4:
Я бы сделал это за несколько проходов. На первом проходе я бы создал список тиков, а затем равномерно распределил их по многим (сотням?) корзины. Если вы заранее знаете, что тики распределены равномерно, вы можете пропустить этот начальный проход. На втором проходе я бы разделил записи на несколько сотен отдельных файлов примерно одинакового размера (эти файлы гораздо меньшего размера представляют группы тиков в нужном вам порядке). Затем я бы отсортировал каждый файл отдельно в памяти. Затем объедините файлы.
Это несколько похоже на hashsort (я думаю).