Сохраняйте постоянные переменные в памяти между запусками скрипта Python - PullRequest
46 голосов
/ 14 июля 2011

Есть ли способ сохранить переменную результата в памяти, чтобы мне не приходилось пересчитывать ее каждый раз при запуске начала моего скрипта? Я выполняю длинную (5-10 секунд) серию точных операций над набором данных (который я читаю с диска) каждый раз, когда запускаю свой сценарий. Это не будет большой проблемой, поскольку я довольно хорошо использую интерактивный редактор для отладки своего кода между запусками; однако иногда интерактивные возможности просто не сокращают его.

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

# Check if variable already created this session
in_mem = var_in_memory() # Returns pointer to var, or False if not in memory yet
if not in_mem:
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    in_mem = store_persistent(result)

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

Какие-нибудь советы по получению полки делают то, что я хочу? Есть альтернативные идеи?

Ответы [ 7 ]

42 голосов
/ 14 июля 2011

Вы можете добиться чего-то подобного, используя глобальную функцию reload для повторного выполнения кода вашего основного скрипта.Вам нужно будет написать скрипт-обертку, который импортирует ваш основной скрипт, запрашивает у него переменную, которую он хочет кэшировать, кэширует копию этого в области видимости модуля скрипта-обертки, а затем, когда вы хотите (когда вы нажимаете ENTER на stdin или что-то еще), он вызывает reload(yourscriptmodule), но на этот раз передает ему кэшированный объект, так что ваш скрипт может обойти дорогостоящие вычисления.Вот краткий пример.

wrapper.py

import sys
import mainscript

part1Cache = None
if __name__ == "__main__":
    while True:
        if not part1Cache:
            part1Cache = mainscript.part1()
        mainscript.part2(part1Cache)
        print "Press enter to re-run the script, CTRL-C to exit"
        sys.stdin.readline()
        reload(mainscript)

mainscript.py

def part1():
    print "part1 expensive computation running"
    return "This was expensive to compute"

def part2(value):
    print "part2 running with %s" % value

Пока wrapper.py запущен, вы можете редактировать mainscript.py, добавлять новый код в функцию part2 и иметь возможность запускать новый код для предварительно вычисленного part1Cache.

6 голосов
/ 14 июля 2011

Если вы хотите сохранить только один объект (или граф объектов) для будущих сессий, модуль shelve, вероятно, является излишним.Просто маринуйте предмет, который вам небезразличен.Сделайте работу и сохраните рассол, если у вас нет файла рассола, или загрузите файл рассола, если он у вас есть.

import os
import cPickle as pickle

pickle_filepath = "/path/to/picklefile.pickle"

if not os.path.exists(pickle_filepath):
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    with open(pickle_filepath, 'w') as pickle_handle:
        pickle.dump(result, pickle_handle)
else:
    with open(pickle_filepath) as pickle_handle:
        result = pickle.load(pickle_handle)
6 голосов
/ 14 июля 2011

Чтобы сохранить данные в памяти, процесс должен продолжаться.Память принадлежит процессу, выполняющему скрипт, а не оболочке.Оболочка не может удерживать память для вас.

Так что, если вы хотите изменить свой код и продолжить процесс, вам придется перезагрузить модули после их изменения.Если какие-либо данные в памяти являются экземпляром класса, который изменяется, вам нужно будет найти способ преобразовать его в экземпляр нового класса.Это немного беспорядок.Не многие языки были когда-либо хороши в этом горячем исправлении (на ум приходит Common Lisp), и есть много шансов, что что-то пойдет не так.

3 голосов
/ 14 июля 2011

Полка Python - это постоянное решение для засоленных (сериализованных) объектов, основанное на файлах. Преимущество в том, что он хранит объекты Python напрямую, а это значит, что API довольно прост.

Если вы действительно хотите избежать использования диска, технология, которую вы ищете, - это «база данных в памяти». Существует несколько альтернатив, см. Этот вопрос SO: база данных в памяти на Python .

1 голос
/ 11 октября 2014

Это решение, зависящее от ОС ...

$mkfifo inpipe

#/usr/bin/python3
#firstprocess.py
complicated_calculation()
while True:
 with open('inpipe') as f:
  try:
   print( exec (f.read()))
  except Exception as e: print(e)

$./first_process.py &
$cat second_process.py > inpipe

Это позволит вам изменять и переопределять переменные в первом процессе, не копируя и не пересчитывая что-либо.Это должно быть наиболее эффективное решение по сравнению с многопроцессорными, memcached, pickle, shelve-модулями или базами данных.

Это действительно хорошо, если вы хотите многократно редактировать и переопределять second_process.py в вашем редакторе или IDE, пока не получите его.правильно, не дожидаясь первого процесса (например, инициализации большого dict и т. д.), который будет выполняться каждый раз, когда вы вносите изменения.

0 голосов
/ 05 апреля 2017

Вы можете запустить постоянный сценарий на сервере через ОС, который загружает / calcs и даже периодически перезагружает / пересчитывает данные sql в структуры памяти какого-либо типа, а затем обрабатывает данные в памяти из другого сценария через сокет .

0 голосов
/ 14 июля 2011

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

Посмотрите на модуль cmd, который облегчает написание программы оболочки. Вы даже можете организовать так, чтобы любые команды, которые не реализованы в вашей оболочке, передавались в системную оболочку для выполнения (без закрытия вашей оболочки). Затем вам нужно будет реализовать какую-то команду, например prun, которая запускает скрипт Python с использованием модуля runpy.

http://docs.python.org/library/runpy.html

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

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