Подтвердить что ты не робот

Как я могу ускорить рассыпку больших объектов, если у меня много ОЗУ?

Это занимает меня до часа, чтобы прочитать структуру данных графика в 1 гигабайте NetworkX, используя cPickle (его 1 ГБ при хранении на диске в виде двоичного файла pickle).

Обратите внимание, что файл быстро загружается в память. Другими словами, если я запустил:

import cPickle as pickle

f = open("bigNetworkXGraph.pickle","rb")
binary_data = f.read() # This part doesn't take long
graph = pickle.loads(binary_data) # This takes ages

Как я могу ускорить эту последнюю операцию?

Обратите внимание, что я попытался собрать данные как при использовании двоичных протоколов (1 и 2), так и, похоже, не имеет большого значения, какой протокол я использую. Также обратите внимание, что хотя я использую вышеприведенную функцию "load" (что означает "load string" ), она загружает двоичные данные, а не ascii-данные.

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

4b9b3361

Ответ 1

Вероятно, вы связаны с созданием/распределением объектов на основе Python, а не самим распаковкой. Если это так, мало что можно сделать, чтобы ускорить это, за исключением создания всех объектов. Вам нужна вся структура сразу? Если нет, вы можете использовать ленивую совокупность структуры данных (например: представлять части структуры по маринованным строкам, а затем расклеивать их только тогда, когда они доступны).

Ответ 2

У меня был большой успех при чтении структуры данных igraph емкостью 750 МБ (бинарный файл pickle) с использованием самой cPickle. Это было достигнуто путем простого обкатки вызова нагрузки на рассол, как указано здесь

Пример фрагмента в вашем случае будет примерно таким:

import cPickle as pickle
import gc

f = open("bigNetworkXGraph.pickle", "rb")

# disable garbage collector
gc.disable()

graph = pickle.load(f)

# enable garbage collector again
gc.enable()
f.close()

Это определенно не самый подходящий способ сделать это, однако это сокращает время, требуемое решительно.
(Для меня он уменьшился с 843,04 до 41,28 с, около 20 раз).

Ответ 3

Почему бы вам не попробовать маршалинг ваших данных и сохранить его в ОЗУ с помощью memcached (например). Да, у него есть некоторые ограничения, но поскольку this > указывает, что маршалинг быстрее (в 20-30 раз), чем травление.

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

Ответ 4

Это смешно.

У меня есть большой словарь ~ 150 МБ (фактически collections.Counter), который я читал и писал с помощью cPickle в двоичном формате.

Письмо заняло около 3 минут.
Я перестал читать его с отметкой 16 минут, когда моя RAM полностью задохнулась.

Теперь я использую маршала, и это требует: написать: ~ 3s
читать: ~ 5 с

Я немного пошутил и наткнулся на эту статью . Думаю, я никогда не смотрел на источник рассола, но он строит целую ВМ для восстановления словаря?
В документации IMHO должна быть заметка о производительности на очень больших объектах.

Ответ 5

Я также пытаюсь ускорить загрузку/хранение графиков networkx. Я использую метод adjacency_graph для преобразования графика в что-то сериализуемое, см., Например, этот код:

from networkx.generators import fast_gnp_random_graph
from networkx.readwrite import json_graph

G = fast_gnp_random_graph(4000, 0.7)

with open('/tmp/graph.pickle', 'wb+') as f:
  data = json_graph.adjacency_data(G)
  pickle.dump(data, f)

with open('/tmp/graph.pickle', 'rb') as f:
  d = pickle.load(f)
  H = json_graph.adjacency_graph(d)

Однако этот метод преобразования adjacency_graph довольно медленный, поэтому время, затрачиваемое на травление, вероятно, теряется при конвертировании.

Так что это фактически не ускоряет работу, облом. Запуск этого кода дает следующие тайминги:

N=1000

    0.666s ~ generating
    0.790s ~ converting
    0.237s ~ storing
    0.295s ~ loading
    1.152s ~ converting

N=2000

    2.761s ~ generating
    3.282s ~ converting
    1.068s ~ storing
    1.105s ~ loading
    4.941s ~ converting

N=3000

    6.377s ~ generating
    7.644s ~ converting
    2.464s ~ storing
    2.393s ~ loading
    12.219s ~ converting

N=4000

    12.458s ~ generating
    19.025s ~ converting
    8.825s ~ storing
    8.921s ~ loading
    27.601s ~ converting

Этот экспоненциальный рост, вероятно, связан с тем, что граф получает экспоненциально большее количество ребер. Вот тест, если вы хотите попробовать себя.

https://gist.github.com/wires/5918834712a64297d7d1

Ответ 6

Возможно, самое лучшее, что вы можете сделать, это разделить большие данные на наименьший объект меньшим, допустим, более чем на 50 МБ, поэтому его можно сохранить в ram и рекомбинировать.

Afaik нет способа автоматического разделения данных через модуль рассола, поэтому вы должны сделать это самостоятельно.

В любом случае, другим способом (что довольно сложно) является использование NoSQL Database, например MongoDB для хранения ваших данных...

Ответ 7

В общем, я обнаружил, что, если это возможно, при сохранении больших объектов на диске в python, гораздо эффективнее использовать numpy ndarrays или scipy.sparse.

Таким образом, для огромных графов, подобных тому, который приведен в примере, я мог бы преобразовать граф в скудную разреженную матрицу (у networkx есть функция, которая делает это, и это не сложно написать), а затем сохранить эту разреженную матрицу в двоичном формат.

Ответ 8

почему бы вам не использовать pickle.load?

f = open('fname', 'rb')
graph = pickle.load(f)