#delphi #оптимизация #хеширование #словари #биоинформатика
Учитывая, что теперь можно спокойно выделять большие объемы памяти внутри TMemoryStream, я вернулся к идее хранения данных геномных исследований, используемых нами внутри TDictionary в файле для будущего повторного использования. Класс определен так: type PosIndex = packed record chr, pos:integer; end; PosIndexData = record gname, rname, promoter: string; count:array[0..NOfTissues-1] of byte; end; TPosDict = class (TDictionary) private procedure SaveToStream(stream: TStream); procedure LoadFromStream(stream: TStream); public procedure SaveToFile(filename:string); procedure LoadFromFile(filename:string); procedure LoadFromZip(AFileName, InnerName: string); procedure SaveToZip(AFileName, InnerName: string); end; Предупреждая вопросы и комментарии в стиле "Зачем нужен TDictionary, когда есть базы данных?", сразу скажу: у нас мобильное (не в плане телефона, а в плане, что оно часто запускается где попало) приложение, мы не можем использовать стационарный сервер БД, как коллега в своём вопросе Как оптимизировать таблицы/запрос в MySQL?, а работа с файловыми БД с нашими объёмами данных, увы, крайне медленна. А вот с TDictionary поиск происходит пусть не мгновенно, но для нас вполне подходяще по времени. Запись в поток (этот метод затем используют и SaveToFile и SaveToZip) происходит так: procedure TPosDict.SaveToStream(stream: TStream); var writer: TWriter; ps:PosIndex; pid:PosIndexData; l:integer; begin writer := TWriter.Create(stream, 4096); l:=sizeof(pid.count); try writer.WriteListBegin; for ps in Self.Keys do begin pid:=Items[ps]; writer.WriteInteger(ps.chr); writer.WriteInteger(ps.pos); writer.WriteString(pid.gname); writer.WriteString(pid.rname); writer.WriteString(pid.promoter); writer.Write(pid.count,l); end; writer.WriteListEnd; finally writer.Free; end; end; Метод быстр, гигабайтные данные сохраняются быстро даже в ZIP-файл. А вот считывание из файла крайне медленно из-за того, что данные добавляются во вновь созданный TDictionary, происходит хэширование и проверка на уникальность: procedure TPosDict.LoadFromStream(stream: TStream); var reader: TReader; ps:PosIndex; pid:PosIndexData; l:integer; begin Clear; l:=sizeof(pid.count); reader := TReader.Create(stream, 9192); try reader.ReadListBegin; while not reader.EndOfList do begin ps.chr:=reader.ReadInteger; ps.pos:=reader.ReadInteger; pid.gname:=reader.ReadString; pid.rname:=reader.ReadString; pid.promoter:=reader.ReadString; reader.Read(pid.count,l); Add(ps,pid); // вот это всё тормозит!!! end; reader.ReadListEnd; finally reader.Free; end; end; Избежать этого, как я понимаю, нельзя. Но ведь это уже было сделано, когда объект существовал ранее, все хэши уже были созданы и работали. Появилась идея: можно ли при сохранении TDictionary как-то сохранить объект целиком, включая хэши, а затем так же восстановить из файла, чтобы не тратилось время на перехэширование. Ну, или другие идеи, как убрать бутылочное горло при восстановлении данных.
Ответы
Ответ 1
Особенность TDictionary в том, что когда заканчивается ёмкость под хэши, он увеличивает размер и в этот момент происходит перехэширование всей имеющийся (на данный момент) коллекции. Поэтому если заранее примерно известен размер коллекции, то этот размер умноженный на 2-3 можно поставить в capacity.
Комментариев нет:
Отправить комментарий