Маршал сбрасывает быстрее, cPickle загружается быстрее - PullRequest
18 голосов
/ 15 декабря 2011

Я реализую программу, которая должна сериализовать и десериализовать большие объекты, поэтому я проводил некоторые тесты с модулями pickle, cPickle и marshal, чтобы выбрать лучший модуль.По пути я нашел кое-что очень интересное:

Я использую dumps, а затем loads (для каждого модуля) в списке диктов, кортежей, целых чисел, чисел с плавающей точкой и строк.

Это результат моего теста:

DUMPING a list of length 7340032
----------------------------------------------------------------------
pickle => 14.675 seconds
length of pickle serialized string: 31457430

cPickle => 2.619 seconds
length of cPickle serialized string: 31457457

marshal => 0.991 seconds
length of marshal serialized string: 117440540

LOADING a list of length: 7340032
----------------------------------------------------------------------
pickle => 13.768 seconds
(same length?) 7340032 == 7340032

cPickle => 2.038 seconds
(same length?) 7340032 == 7340032

marshal => 6.378 seconds
(same length?) 7340032 == 7340032

Итак, из этих результатов мы видим, что marshal был чрезвычайно быстрым в демпинге части теста:

в 14,8 раза быстрее, чем pickle и в 2,6 раза быстрее, чем cPickle.

Но, к моему большому удивлению, marshal был намного медленнее, чем cPickle в загрузке часть:

в 2,2 раза быстрее, чем pickle, но в 3,1 раза медленнее, чем cPickle.

Что касается оперативной памяти, производительность marshal при загрузке также была очень неэффективной:

Ubuntu System Monitor

Я предполагаю причину, по которой загрузка с marshalтакая медленная скорость как-то связана с длиной ее сериализованной строки (намного больше, чем pickle и cPickle).

  • Почему marshal сбрасывает быстрее и загружает медленнее?
  • Почему сериализованная строка marshal такая длинная?
  • Почему загрузка marshal в ОЗУ так неэффективна?
  • Есть ли способ улучшить производительность загрузки marshal?
  • Есть ли способ объединить marshal быстрый сброс с cPickle быстрой загрузкой?

Ответы [ 6 ]

19 голосов
/ 18 декабря 2011

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

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

Что касается того факта, что marshal может быть несовместим с другими версиями Python, вы, как правило, должны использовать cPickle:

"Это не обычный модуль" постоянства ".Для общего сохранения и передачи объектов Python через вызовы RPC, см. Модули pickle и shelve. Модуль marshal существует главным образом для поддержки чтения и записи «псевдоскомпилированного» кода для модулей Python .pyc-файлов Python. Поэтому резервный компонент Python резервируется.право изменять формат маршала обратно несовместимыми способами в случае необходимости. Если вы сериализуете и десериализуете объекты Python, используйте вместо этого модуль pickle - производительность сопоставима, независимость от версии гарантируется, а pickle поддерживает значительно более широкийРяд объектов, чем маршал. "( документация по питону о маршале )

13 голосов
/ 14 февраля 2012

Некоторые люди могут подумать, что это слишком взломано, но я добился большого успеха, просто упаковав вызовы dump-дампов в gc.disable () и gc.enable (). Например, приведенные ниже фрагменты, содержащие список словарей размером ~ 50 МБ, увеличиваются с 78 секунд до 4.

#  not a complete example....
gc.disable()
cPickle.dump(params,fout,cPickle.HIGHEST_PROTOCOL)         
fout.close()               
gc.enable()
9 голосов
/ 23 декабря 2011

Разница между этими тестами дает одну идею для ускорения cPickle:

Input: ["This is a string of 33 characters" for _ in xrange(1000000)]
cPickle dumps 0.199 s loads 0.099 s 2002041 bytes
marshal dumps 0.368 s loads 0.138 s 38000005 bytes

Input: ["This is a string of 33 "+"characters" for _ in xrange(1000000)]
cPickle dumps 1.374 s loads 0.550 s 40001244 bytes
marshal dumps 0.361 s loads 0.141 s 38000005 bytes

В первом случае список повторяет ту же строку.Второй список эквивалентен, но каждая строка является отдельным объектом, потому что это результат выражения.Теперь, если вы изначально читаете свои данные из внешнего источника, вы можете рассмотреть некоторую дедупликацию строк.

5 голосов
/ 27 февраля 2013

Вы можете сделать cPickle cca.В 50 раз (!) Быстрее, создав экземпляр cPickle.Pickler, а затем установив недокументированный параметр 'fast' в значение 1:

outfile = open('outfile.pickle')
fastPickler = cPickle.Pickler(outfile, cPickle.HIGHEST_PROTOCOL)
fastPickler.fast = 1
fastPickler.dump(myHugeObject)
outfile.close()

Но если ваш myHugeObject имеет циклические ссылки, метод dump никогда не завершится.

3 голосов
/ 23 июня 2013

Вы можете повысить эффективность хранения, сжав результат сериализации.

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

Тест, приведенный ниже, был сделан, чтобы доказать, что сжатие ускорит процесс десериализации. Результат оказался не таким, как ожидалось, поскольку машина была оснащена SSD. На оборудовании HHD сжатие данных с использованием lz4 будет быстрее, поскольку чтение с диска в среднем составляет 60-70 МБ / с.

LZ4: при снижении скорости на 18% выход сжатия составляет 77,6% дополнительного хранилища.

marshal - compression speed time
Bz2 7.492605924606323  10363490
Lz4 1.3733329772949219 46018121
--- 1.126852035522461 205618472
cPickle - compression speed time
Bz2 15.488649845123291 10650522
Lz4 9.192650079727173  55388264
--- 8.839831113815308 204340701
3 голосов
/ 20 декабря 2011

Как вы можете видеть, выход, полученный с помощью cPickle.dump, имеет около 1/4 длины вывода, полученного с помощью marshal.dump.Это означает, что cPickle должен использовать более сложный алгоритм для сброса данных при удалении ненужных вещей.При загрузке выгруженного списка, marshal должен обрабатывать гораздо больше данных, в то время как cPickle может обрабатывать его данные быстро, поскольку требуется меньше данных для анализа.

Что касается того, что marshal можетчтобы быть несовместимым с другими версиями Python, вы должны обычно использовать cPickle:

"Это не общий модуль" постоянства ". Для общего сохранения и передачи объектов Python с помощью вызовов RPC см.Модули pickle и shelve. Модуль marshal существует главным образом для поддержки чтения и записи «псевдоскомпилированного» кода для модулей Python для файлов .pyc, поэтому сопровождающие Python оставляют за собой право изменять формат маршала обратными несовместимыми способами в случае необходимости.Если вы сериализуете и десериализуете объекты Python, используйте вместо этого модуль pickle - производительность сопоставима, независимость от версии гарантирована, а pickle поддерживает значительно более широкий диапазон объектов, чем маршал ».( документация по питону о маршале )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...