Добавлен , не публикуется
UPD. полностью отказался от строк, остальное актуально

Сегодня я хотел бы рассказать о работе с секторами в JARG.
Как и во многих других проектах, карта в JARG разделена на сектора, был выбран размер 25, привычные степени двойки плохо подходили - 16 слишком мало, 32 - слишком много.
Изначально Система хранения секторов выглядела очень просто: словарь активных секторов, которые выводятся непосредственно, и словарь всех секторов. При запросе любого блока или сектора поиск производился сначала в списке активных, а затем в списке всех, если сектор не находился, то он генерировался.
Такая система была слабой во всех отношениях: нет абстракции доступа, невозможна фоновая генерация, неактивные сектора занимают огромный объем памяти (примерно по 70KiB на сектор из за большого количества списков и избыточной информации, присущей C#)
Было принято решение переделать систему.
Первым улучшением стало абстрагирование класса, который занимается генерацией и передачей секторов классу игры - LevelWorker, запускает фоновый поток обработки всех запросов, а также занимающийся фоновой генерацией карты.
Вместо хранения секторов в виде экземпляров класса MapSector было выбрано хранение в сериализованном, сжатом виде. Сначала для каждого списка (блоков, полов, юнитов) формируется словарь, чтобы обозначать длинные идентификаторы одной цифрой, затем они сжимаются при помощи RLE (крайне успешно). В результате затраты на хранение сектора снизились с 70KiB, в среднем, до 800 B, а также полностью отпала необходимость подготовки секторов к сохранению на диск.
Сектора, которые запрашиваются игрой, создаются в виде экземпляра класса MapSector, из сериализованного представления, при возвращении их обратно на хранение, экземпляр сериализуется и разрушается..
К слову, адресация происходит по hash пары координат {x, y}, так что сложность поиска в любом из списков O(1)
Так же выделение абстракции позволило легко перенести LevelWorker на сервер без каких-либо серьезных изменений.
О генерации карты я расскажу в одной из следующих заметок.
`
ОЖИДАНИЕ РЕКЛАМЫ...
29
Чем обусловленно ожидание в 300 мс?
Вместо хранения секторов в виде экземпляров класса MapSector было выбрано хранение в виде строки, в сжатом виде. Сначала для каждого списка (блоков, полов, юнитов) формируется словарь, чтобы обозначать длинные идентификаторы одной цифрой, затем они сжимаются при помощи RLE (крайне успешно). В результате затраты на хранение сектора снизились с 70KiB, в среднем, до 800 B, а также полностью отпала необходимость подготовки секторов к сохранению на диск.
Ууу..... зачеееммм???? Неужели тебе важнее каких то там пару килобайт, по сравнению с затратой времени на упаковку и распаковку строк? Строки очень плохое решение.
29
К слову, адресация происходит по hash пары координат {x, y}, так что сложность поиска в любом из списков O(1)
Кст, если мне не изменяет память, то хэш структуры занимают много памяти. Тобишь ты сам себе противоречишь. Одно место оптимизируешь по памяти в ущерб времени, другое наоборот...
И вообще. Преждевременная оптимизация корень всех зол
14
alexprey:
Ууу..... зачеееммм???? Неужели тебе важнее каких то там пару килобайт, по сравнению с затратой времени на упаковку и распаковку строк? Строки очень плохое решение.
Во-первых затраты на хранение снизились не на пару килобайт, а на 69 килобайт или в 100 раз. Во вторых сериализация -- это отдельный метод, сделать двоичную сериализацию никто не запрещает. В-третьих, скорость упаковки\распаковки не слишком важна, все равно гораздо больше времени уйдет на ожидание ответа сервера да и происходит распаковка на фоне.
P.S. Накладные расходы на строку -- 14 (26 для x64) байт, плюс до 4 байт на выравнивание.
P.P.S. Также стоить добавить, что все Id -- это интернированные, во время загрузки базы блоков, строки.
Кст, если мне не изменяет память, то хэш структуры занимают много памяти. Тобишь ты сам себе противоречишь. Одно место оптимизируешь по памяти в ущерб времени, другое наоборот...
Был бы рад узнать решение для разреженного массива неограниченного размера, лучше, чем хеш-таблица
К слову, какие-то пару килобайт выходили в ограничение по памяти для приложения где-то за пол часа.
Doc:
Очень плохие решения уровня варкрафта
Предложения?
Замерил время на сериализацию\десериализацию: UnstoreSector TotalMilliseconds = 1.0504 (в основном из-за выделения памяти, пул секторов сократит это время тоже до 0.25 мс), StoreSector TotalMilliseconds = 0.2683, на ноутбуке 7ми летней давности
Чтобы оставить комментарий, пожалуйста, войдите на сайт.