在Python脚本运行之间将持久变量保留在内存中

时间:2011-07-14 01:56:48

标签: python variables memory

有没有办法将结果变量保存在内存中,所以每次运行脚本开头时我都不必重新计算它? 每次运行脚本时,我都会对数据集(我从磁盘上读取)执行一系列(5-10秒)的精确操作。 这不会是一个太大的问题,因为我很擅长使用交互式编辑器在运行之间调试我的代码;但有时互动能力并没有削减它。

我知道我可以把我的结果写到磁盘上的文件中,但是如果可能的话,我想避免这样做。这应该是一个解决方案,它在我第一次运行脚本时生成一个变量,并将其保存在内存中,直到shell本身关闭或直到我明确告诉它失败。像这样:

# 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模块可能就是我在这里寻找的东西,但看起来为了打开一个搁置变量,我必须为持久对象指定一个文件名,并且所以我不确定这是否正是我正在寻找的。

任何关于搁置做我想做的事情的提示?还有其他想法吗?

7 个答案:

答案 0 :(得分:41)

您可以使用reload全局函数重新执行主脚本的代码来实现这样的功能。您需要编写一个包装器脚本来导入您的主脚本,询问它要缓存的变量,在包装器脚本的模块范围内缓存它的副本,然后在您需要时(当您在stdin或其他任何地方点击ENTER时) ),它调用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运行新代码。

答案 1 :(得分:6)

要将数据保存在内存中,该过程必须继续运行。内存属于运行脚本的进程,而不属于shell。 shell无法为你保存内存。

因此,如果您想更改代码并保持流程运行,则必须在更改模块时重新加载模块。如果内存中的任何数据是更改的类的实例,则必须找到将其转换为新类的实例的方法。这有点乱。没有多少语言能够在这种热补丁中获得好处(Common Lisp浮现在脑海中),并且有很多机会出错。

答案 2 :(得分:6)

如果您只想在将来的会话中保留一个对象(或对象图),则搁置模块可能过度。只需腌制你关心的对象。如果没有pickle文件,请做好工作并保存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)

答案 3 :(得分:3)

Python的搁置是针对pickle(序列化)对象的持久性解决方案,并且是基于文件的。优点是它直接存储Python对象,这意味着API非常简单。

如果您真的想要避开磁盘,那么您正在寻找的技术就是“内存数据库”。存在几种替代方案,请参阅此SO问题:in-memory database in Python

答案 4 :(得分:1)

这是一个依赖于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模块或数据库相比,它应该是最有效的解决方案。

如果你想在你的编辑器或IDE中迭代地编辑和重新定义second_process.py直到你拥有它而不必等待第一个进程(例如初始化一个大的dict等)来执行每次都非常好你做了一个改变。

答案 5 :(得分:0)

您可以这样做,但必须使用Python shell。换句话说,用于启动Python脚本的shell必须是Python进程。然后,任何全局变量或类都将存在,直到您关闭shell。

查看cmd模块,这样可以轻松编写shell程序。您甚至可以安排将shell中未实现的任何命令传递给系统shell以执行(不关闭shell)。然后你必须实现某种命令,例如prun,它使用runpy模块运行Python脚本。

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

您需要使用init_globals参数将特殊数据传递给程序的命名空间,理想情况下是dict或单个类实例。

答案 6 :(得分:0)

您可以通过加载/计算的操作系统在服务器上运行持久脚本,甚至可以定期将sql数据重新加载/重新计算到某种内存结构中,然后通过套接字从其他脚本中获取内存中的数据