Быстрая сериализация JSON (и сравнение с Pickle) для кластерных вычислений в Python? - PullRequest
5 голосов
/ 20 апреля 2010

У меня есть набор точек данных, каждая из которых описывается словарем. Обработка каждой точки данных является независимой, и я отправляю каждую из них как отдельную работу в кластер. Каждая точка данных имеет уникальное имя, и моя оболочка представления кластера просто вызывает скрипт, который берет имя точки данных и файл, описывающий все точки данных. Затем этот сценарий обращается к точке данных из файла и выполняет вычисления.

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

Я попытался использовать JSONpickle, используя следующий метод, для сериализации словаря, описывающего все точки данных в файле:

def json_serialize(obj, filename, use_jsonpickle=True):
    f = open(filename, 'w')
    if use_jsonpickle:
    import jsonpickle
    json_obj = jsonpickle.encode(obj)
    f.write(json_obj)
    else:
    simplejson.dump(obj, f, indent=1)   
    f.close()

Словарь содержит очень простые объекты (списки, строки, числа с плавающей запятой и т. Д.) И имеет в общей сложности 54 000 ключей. Размер файла json составляет ~ 20 мегабайт.

Загрузка этого файла в память занимает ~ 20 секунд, что мне кажется очень медленным. Я переключился на использование pickle с тем же самым объектом и обнаружил, что он генерирует файл размером около 7,8 мегабайт и может быть загружен за ~ 1-2 секунды. Это значительное улучшение, но все равно кажется, что загрузка небольшого объекта (менее 100 000 записей) должна быть быстрее. Кроме того, рассол не читается человеком, что было для меня большим преимуществом JSON.

Есть ли способ использовать JSON для получения аналогичных или лучших ускорений? Если нет, у вас есть другие идеи по структурированию?

(Является ли правильным решением просто «нарезать» файл, описывающий каждое событие, в отдельный файл и передать его в сценарий, выполняющий точку данных в кластерном задании? Похоже, это может привести к увеличению количества файлов ).

спасибо.

Ответы [ 2 ]

7 голосов
/ 20 апреля 2010

marshal самый быстрый, но pickle как таковой нет - возможно, вы имеете в виду cPickle (что довольно быстро, особенно с протоколом -1). Итак, кроме проблем с читабельностью, вот код, демонстрирующий различные возможности:

import pickle
import cPickle
import marshal
import json

def maked(N=5400):
  d = {}
  for x in range(N):
    k = 'key%d' % x
    v = [x] * 5
    d[k] = v
  return d
d = maked()

def marsh():
  return marshal.dumps(d)

def pick():
  return pickle.dumps(d)

def pick1():
  return pickle.dumps(d, -1)

def cpick():
  return cPickle.dumps(d)

def cpick1():
  return cPickle.dumps(d, -1)

def jso():
  return json.dumps(d)

def rep():
  return repr(d)

и вот их скорость на моем ноутбуке:

$ py26 -mtimeit -s'import pik' 'pik.marsh()'
1000 loops, best of 3: 1.56 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.pick()'
10 loops, best of 3: 173 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.pick1()'
10 loops, best of 3: 241 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.cpick()'
10 loops, best of 3: 21.8 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.cpick1()'
100 loops, best of 3: 10 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.jso()'
10 loops, best of 3: 138 msec per loop
$ py26 -mtimeit -s'import pik' 'pik.rep()'
100 loops, best of 3: 13.1 msec per loop

Таким образом, вы можете иметь удобочитаемость и , в десять раз превышающую скорость json.dumps с repr (вы жертвуете простотой анализа из Javascript и других языков); Вы можете иметь абсолютную максимальную скорость с marshal, почти в 90 раз быстрее, чем json; cPickle предлагает гораздо больше универсальности (с точки зрения того, что вы можете сериализовать), чем json или marshal, но если вы никогда не собираетесь использовать эту общность, то вы также можете пойти на marshal (или repr, если удобочитаемость выше скорости).

Что касается вашей идеи "нарезки", то вместо множества файлов вы можете рассмотреть базу данных (множество записей) - вы даже можете уйти без реальной сериализации, если вы работаете с данными, которые имеет некоторую узнаваемую «схему».

1 голос
/ 20 апреля 2010

Я думаю, что вы сталкиваетесь здесь с компромиссом: удобочитаемость достигается ценой производительности и большого размера файла. Таким образом, из всех методов сериализации, доступных в Python, JSON не только самый читаемый, но и самый медленный.

Если бы мне пришлось стремиться к производительности (и компактности файлов), я бы выбрал marshall . Вы можете либо упорядочить весь набор с помощью dump () и load () , либо, основываясь на своей идее нарезки, выделить отдельные части набора данных в отдельные файлы. Таким образом, вы открываете дверь для распараллеливания обработки данных - если вы чувствуете такую ​​склонность.

Конечно, в документации есть все виды ограничений и предупреждений, поэтому, если вы решите не рисковать, перейдите на pickle .

...