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

Сохранять постоянные переменные в памяти между запусками Python script

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

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

# 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 может быть тем, что я ищу здесь, но выглядит так, чтобы открыть переменную полки, которую я бы нужно указать имя файла для постоянного объекта, и поэтому я не уверен, действительно ли это то, что я ищу.

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

4b9b3361

Ответ 1

Вы можете добиться чего-то подобного, используя глобальную функцию reload для повторного выполнения вашего основного кода script. Вам нужно будет написать обертку script, которая импортирует ваш основной script, запрашивает у нее переменную, которую он хочет кэшировать, кэширует копию этого содержимого в оболочке script, а затем, когда вы хотите (когда вы нажмите 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.

Ответ 2

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

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

Ответ 3

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

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)

Ответ 4

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

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

Ответ 5

Это зависимое от os решение...

$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 и т.д.) для выполнения каждый раз вы вносите изменения.

Ответ 6

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

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

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

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

Ответ 7

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