Соління або json?


114

Мені потрібно зберегти на диску маленький dictоб’єкт, чиї ключі мають тип strі значення ints, а потім відновити його . Щось на зразок цього:

{'juanjo': 2, 'pedro':99, 'other': 333}

Який найкращий варіант і чому? Серіалізувати його за допомогою pickleабо з simplejson?

Я використовую Python 2.6.


перетворити його в що? Також, в якому сенсі краще ?
— SilentGhost

10
У 2.6 ви б не використовували simplejson, ви б використовували вбудований jsonмодуль (який має той самий точний інтерфейс).
— Майк Грем

5
"найкращий"? Найкраще для чого? Швидкість? Складність? Гнучкість? Вартість?
— S.Lott


Відповіді:


68

Якщо у вас немає жодних вимог щодо сумісності (наприклад, ви просто збираєтеся використовувати дані з Python), а двійковий формат прекрасний, перейдіть з cPickle, який дає вам дуже швидку серіалізацію об'єктів Python.

Якщо вам потрібна сумісність або ви хочете, щоб текстовий формат зберігав ваші дані, перейдіть з JSON (або іншим відповідним форматом залежно від ваших обмежень).


48
Здається, JSON швидше, ніж cPickle.
— мак

5
У моїй відповіді підкреслюються проблеми, які, на мою думку, є найбільш важливими для врахування при виборі будь-якого рішення. Я не претендую на те, щоб бути швидшим за інших. Якщо JSON швидше І іншим чином підходить, ідіть з JSON! (Тобто, немає причини для вашого голосування.)
— Håvard S

10
Моя думка: немає жодної реальної причини для використання cPickle(або pickle) на основі вашого приміщення в JSON. Коли я вперше прочитав вашу відповідь, я подумав, що причиною може бути швидкість, але оскільки це не так ... :)
— мак

14
Тест, на який посилається @mac, лише тестує рядки. Я перевірив str, int та float окремо і з’ясував, що json повільніше, ніж cPickle з плаваючою серіалізацією, але швидше з несеріалізацією float. Для int (і str), json швидший обома способами. Дані та код: gist.github.com/marians/f1314446b8bf4d34e782
— Маріан

24
Останній протокол cPickle тепер швидший, ніж JSON. Оголошений коментар про те, що JSON проходить швидше, застарів на кілька років. stackoverflow.com/a/39607169/1007353
— JDiMatteo

104

Я віддаю перевагу JSON над солінням для своєї серіалізації. Скасування відбору може запускати довільний код, а використання pickleдля передачі даних між програмами або зберігання даних між сеансами - це отвір у захисті. JSON не вводить отвір у захисті та стандартизується, тому дані можуть бути доступними програмами на різних мовах, якщо вам це потрібно.


Дякую. У будь-якому випадку я буду демпінгу та завантаження в тій же програмі.
— Хуанхо Конті

2
Хоча ризики для безпеки можуть бути низькими у вашому поточному застосуванні, JSON дозволяє повністю закрити ціле.
— Майк Грем

4
Можна створити маринований вірус, який маринує все, що маринується після завантаження. З json це неможливо.
— Користувач

2
Окрім безпеки, JSON має додаткову перевагу в тому, що робить міграцію легкою, тому ви можете завантажувати дані, збережені в старій версії програми. Тим часом ви могли додати поле або замінити цілу підструктуру. Писати такий перетворювач (міграція) для dict / list прямо вперед, але з Pickle вам важко буде завантажувати його в першу чергу, перш ніж ви навіть можете думати про перетворення.
— вог

2
Я не замислювався над цим аспектом (безпека та можливість маринованих об’єктів запускати довільний код). Дякуємо, що вказали на це!
— CaffeinatedMike

43

Вам також може здатися це цікавим, з кількома діаграмами для порівняння: http://kovshenin.com/archives/pickle-vs-json-which-is-faster/


1
У статті порівнюється продуктивність, що стосується лише рядків. Ось сценарій, який ви можете запустити, щоб окремо протестувати рядки, плаваючі та вбудовані елементи
— Маріан


20

Якщо ви переймаєтесь швидкістю та простором, використовуйте cPickle, оскільки cPickle швидший, ніж JSON.

Якщо ви більше переймаєтесь інтероперабельністю, безпекою та / або читабельністю для людей, тоді використовуйте JSON.


Результати тестів, на які посилаються інші відповіді, були записані в 2010 році, а оновлені тести в 2016 році за допомогою протоколу 2 cPickle показують:

  • cPickle 3.8x швидше завантаження
  • cPickle на 1,5 рази швидше читання
  • cPickle трохи менше кодування

Відтворіть це самостійно за допомогою цієї суті , яка базується на орієнтирі Костянтина, на який посилається в інших відповідях, але використовуючи cPickle з протоколом 2 замість соління, а також використовуйте json замість simplejson (оскільки json швидший, ніж Simplejson ), наприклад

wget https://gist.github.com/jdimatteo/af317ef24ccf1b3fa91f4399902bb534/raw/03e8dbab11b5605bc572bc117c8ac34cfa959a70/pickle_vs_json.py
python pickle_vs_json.py

Результати з python 2.7 на гідному процесорі Xeon 2015 року:

Dir Entries Method  Time    Length

dump    10  JSON    0.017   1484510
load    10  JSON    0.375   -
dump    10  Pickle  0.011   1428790
load    10  Pickle  0.098   -
dump    20  JSON    0.036   2969020
load    20  JSON    1.498   -
dump    20  Pickle  0.022   2857580
load    20  Pickle  0.394   -
dump    50  JSON    0.079   7422550
load    50  JSON    9.485   -
dump    50  Pickle  0.055   7143950
load    50  Pickle  2.518   -
dump    100 JSON    0.165   14845100
load    100 JSON    37.730  -
dump    100 Pickle  0.107   14287900
load    100 Pickle  9.907   -

Python 3.4 з маринованим протоколом 3 ще швидший.


11

JSON або соління? Як щодо JSON та соління! Можна використовувати jsonpickle. Він простий у використанні, а файл на диску читабельний, тому що це JSON.

http://jsonpickle.github.com/


2
Хтось орієнтував його на ефективність проти варіантів? Чи порівняна вона по продуктивності з сирим json, як це бачиться тут benfrederickson.com/dont-pickle-your-data ?
— Хосеп Валлс

Це не широкий діапазон, але у мене була існуюча гра, де вона економила рівні, використовуючи соління (python3). Мені хотілося спробувати jsonpickle для людського читаного аспекту - однак збереження рівня були, на жаль, набагато повільнішими. 1597 мс для jsonpickle і 88 мс або звичайний соління на рівні економ. Для рівневого навантаження 1604 мс для jsonpickle і 388 для соління. Шкода, як мені подобається, що люди читають, економить.
— Ніл Макгілл

Я перевірив це в нашій торговій системі, читабельність - це приблизно 2 рази серіалізація + штраф за швидкість десеріалізації порівняно з солінням. Хоча чудово для всього іншого.
— Нуреттін

6

Я спробував декілька методів і з'ясував, що використання cPickle із встановленням аргументу протоколу методу damps як: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)є найшвидшим методом демпінгу.

import msgpack
import json
import pickle
import timeit
import cPickle
import numpy as np

num_tests = 10

obj = np.random.normal(0.5, 1, [240, 320, 3])

command = 'pickle.dumps(obj)'
setup = 'from __main__ import pickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("pickle:  %f seconds" % result)

command = 'cPickle.dumps(obj)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle:   %f seconds" % result)


command = 'cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle highest:   %f seconds" % result)

command = 'json.dumps(obj.tolist())'
setup = 'from __main__ import json, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("json:   %f seconds" % result)


command = 'msgpack.packb(obj.tolist())'
setup = 'from __main__ import msgpack, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("msgpack:   %f seconds" % result)

Вихід:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds

4

Особисто я віддаю перевагу JSON, оскільки дані читаються людиною . Однозначно, якщо вам потрібно серіалізувати щось, що JSON не візьме, то використовуйте соління.

Але для більшості сховищ даних вам не потрібно буде серіалізувати що-небудь дивне, і JSON набагато простіше і завжди дозволяє відкрити його в текстовому редакторі та перевірити дані самостійно.

Швидкість приємна, але для більшості наборів даних різниця незначна; Python взагалі не надто швидкий.



1
Правда. Але для 100елементів у списку різниця абсолютно незначна для людського ока. Однозначно відрізняється при роботі з більшими наборами даних.
— rickcnagy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.