Прожорливый JSON

Часто промежуточные результаты каких-нибудь долгих вычислений, которые нужно сделать один раз, сохраняю в JSON. Например могу пройтись по всем записям в большой таблице, посчитать серию параметров, сохранить в JSON, скачать файл локально и потом считать какие-нибудь агрегированные данные.
Однажды, считая большой отчет, наткнулся на необычайную прожорливость JSON.load
на сравнительно небольших данных.
Промоделируем ситуацию (размер занимаемой памяти на вашем компьютере может отличаться, но я проверил на маке и на линуксе). Сгенерируем json-файл:
# => 11 MB
a = {key: [{k: 1, value: "strng"}]*2_000_000}
# => 26 MB
t = JSON.dump(a)
# => 54 MB
File.write("big.json", t)
Теперь его прочитаем:
# => 11 MB
t = File.read("big.json")
# => 57 MB
x = JSON.load(t)
# => 1600 MB
массив, который в руби занимает 15 мегабайт, после восстановления раздувается в 100 раз (при использовании
библиотеки
oj
в 50 раз). Самое противное в этой ситуации, что json на 1 гигабайт сохранить вы сможете,
а прочитать уже нет - памяти не хватит. Особенно неприятно об этом узнать
после нескольких часов вычислений.
Чтобы обойти эту проблему можно использовать пару Marshal.dump/load
, которая работает гораздо быстрее и не занимает лишней памяти.
Однако marshal-файл не получится посмотреть глазами, нормально хранить в системе контроля версии или погрепать. Поэтому универсального решения не существует, все зависит от задачи.
Просто помните, когда сохраняете большой JSON-файл, а хватит ли
вам духа и оперативной памяти, чтобы его прочитать?