Частое обновление сохраненных данных для численного эксперимента с использованием Python

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

data_dict = {}                       # maybe a dictionary is not the best choice
for j in parameters:                 # j = (alpha, beta, gamma) and cycle through
    for k in number_of_experiments:  # lots of experiments (10^4)
        file = open('storage.pkl', 'ab')
        data = experiment()          # experiment returns some numerical value
                                     # experiment takes ~ 1 seconds, but increase
                                     # as parameters scale
        data_dict.setdefault(j, []).append(data)
        pickle.dump(data_dict, file)
        file.close()

Вопросы:

  1. Является ли полка лучшим выбором здесь? Или какая-то другая библиотека Python, о которой я не знаю?
  2. Я использую data dict, потому что его проще кодировать и он более гибкий, если мне нужно что-то изменить, когда я провожу больше экспериментов. Было бы огромным преимуществом использовать предварительно выделенный массив?
  3. Влияет ли открытие и закрытие файлов на время выполнения? Я делаю это, чтобы я мог проверять прогресс в дополнение к текстовым журналам, которые я настроил.

Спасибо за все что ты сделал для меня!


person Charlie    schedule 27.06.2014    source источник
comment
Для ваших открытых накладных расходов я получаю около 39 микросекунд для открытия с параметрами «ab» для файла в несколько байтов, 41 микросекунд (нас) для 1 КБ, 44 микросекунд для ~ 10 КБ, 158 мкс для 100 КБ и 2 МБ и 162 мкс для 20 МБ файлов. . Так что не так уж много, если размер вашего файла меньше 20 МБ ... Это с SSD, так что YMMV.   -  person dhj    schedule 29.06.2014


Ответы (2)


  1. Предположим, что вы используете numpy для своих числовых экспериментов вместо pickle Я бы предложил использовать numpy.savez .
  2. Сохраняйте простоту и выполняйте оптимизацию только в том случае, если вы чувствуете, что скрипт работает слишком долго.
  3. Открытие и закрытие файлов влияет на время выполнения, но в любом случае лучше иметь резервную копию.

И я бы использовал collections.defaultdict(list) вместо простых dict и setdefault.

person newtover    schedule 27.06.2014

Однако полка, вероятно, не лучший выбор...

Вы можете попробовать использовать klepto или joblib. Оба хорошо кэшируют результаты и могут использовать эффективные форматы хранения.

И joblib, и klepto могут сохранять результаты в файл на диске или в каталог. Оба могут также использовать формат внутреннего хранилища numpy и/или сжатие при сохранении… а также сохранять в файлы с отображением памяти, если хотите.

Если вы используете klepto, он берет ключ словаря в качестве имени файла и сохраняет значение в качестве содержимого. С klepto вы также можете выбрать, хотите ли вы использовать pickle или json или какой-либо другой формат хранения.

Python 2.7.7 (default, Jun  2 2014, 01:33:50) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import klepto
>>> data_dict = klepto.archives.dir_archive('storage', cached=False, serialized=True)     
>>> import string
>>> import random
>>> for j in string.ascii_letters:
...   for k in range(1000):
...     data_dict.setdefault(j, []).append([int(10*random.random()) for i in range(3)])
... 
>>> 

Это создаст каталог с именем storage, который содержит файлы с маринованными файлами, по одному для каждого ключа вашего data_dict. Есть ключевые слова для использования файлов memmap, а также для уровня сжатия. Если вы выберете cached=False, то вместо создания дампа в файл каждый раз, когда вы записываете в data_dict, вы будете каждый раз записывать в память… и затем вы можете использовать data_dict.dump() для вывода на диск всякий раз, когда вы выберете… или вы можете выбрать предел памяти, который, когда вы нажмете его, вы сбросите на диск. Кроме того, вы также можете выбрать стратегию кэширования (например, lru или lfu), чтобы решить, какие ключи вы хотите удалить из памяти и сбросить на диск.

Получите klepto здесь: https://github.com/uqfoundation

или получите joblib здесь: https://github.com/joblib/joblib

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

Влияет ли открытие и закрытие файлов на время выполнения? Да. Если вы используете klepto, вы можете установить степень детализации, когда вы хотите выгружать дамп на диск. Затем вы можете выбрать компромисс между скоростью и промежуточным хранением результатов.

person Mike McKerns    schedule 28.06.2014
comment
Спасибо за этот мини-урок! Действительно ценю это. - person Charlie; 01.07.2014
comment
Добро пожаловать. Я, вероятно, помню достаточно о joblib, чтобы добавить пример этого, если вы обнаружите, что вышеизложенное не работает для вас. - person Mike McKerns; 01.07.2014
comment
Привет, Майк, знайте, что этот вопрос был официально закрыт, но недавно столкнулся с этой проблемой и я довольно застрял. Я отправил его по электронной почте своим знающим друзьям в надежде, что кто-нибудь ответит на него, но пока не повезло. Мне интересно, сталкивались ли вы с этой трудностью с такими данными и как вы ее решили. На самом деле, я комментирую здесь в надежде, что один из этих модулей действительно может исправить ситуацию. - person Charlie; 03.10.2014
comment
В итоге я оптимизировал фактический код Python, поэтому мне не нужно было реализовывать хранилище данных с использованием модулей, которые вы предложили для ускорения времени выполнения; отсюда и причина, по которой я остановился на рассоле, чтобы заставить его работать с первого раза! - person Charlie; 03.10.2014