在两次运行Python脚本之间将持久变量保存在内存中
有什么方法可以将结果变量保存在内存中,所以我不必每次运行脚本的开头都重新计算它?每次运行脚本时,我都会对数据集(从磁盘上读取)进行一系列(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个解决方案
43 votes
您可以使用wrapper.py全局函数来重新执行主脚本的代码,从而实现类似目的。 您将需要编写一个包装器脚本,该脚本会导入您的主脚本,向其询问要缓存的变量,然后在包装器脚本的模块范围内缓存该副本,然后在需要时(当您在stdin上按Enter或其他命令时) ),它调用mainscript.py,但这一次将缓存的对象传递给它,以便您的脚本可以绕过昂贵的计算。 这是一个简单的例子。
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运行新代码。
Peter Lyons answered 2020-02-04T05:25:08Z
6 votes
为了将数据保留在内存中,该进程必须继续运行。 内存属于运行脚本的进程,而不属于Shell。 Shell无法为您保存内存。
因此,如果要更改代码并保持进程运行,则必须在更改模块后重新加载模块。 如果内存中的任何数据是更改的类的实例,则必须找到一种将其转换为新类的实例的方法。 有点混乱。 在这种热修补中,很少有语言能胜任(想到Lisp),并且出错的可能性很大。
Dietrich Epp answered 2020-02-04T05:25:34Z
6 votes
如果您只想保留一个对象(或对象图)供以后的会话使用,则搁置模块可能会显得过大。 只需腌制您关心的对象。 如果没有泡菜文件,则进行工作并保存泡菜;如果有泡菜文件,则将其加载。
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)
Matt Anderson answered 2020-02-04T05:25:54Z
3 votes
Python的货架是用于腌制(序列化)对象的持久性解决方案,并且是基于文件的。 优点是它直接存储Python对象,这意味着该API非常简单。
如果您真的想避免使用磁盘,那么您正在寻找的技术是“内存数据库”。 存在几种选择,请参见以下SO问题:Python中的内存数据库。
Ray Toal answered 2020-02-04T05:26:19Z
1 votes
这是一个依赖于操作系统的解决方案...
$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
这样,您就可以在第一个过程中更改和重新定义变量,而无需复制或重新计算任何内容。 与多处理,内存缓存,泡菜,搁置模块或数据库相比,它应该是最有效的解决方案。
如果您想在编辑器或IDE中迭代地编辑和重新定义second_process.py,直到您正确使用它,而不必等到第一个进程(例如,初始化一个大字典等)每次执行一次,它都非常好。 更改。
John answered 2020-02-04T05:26:48Z
0 votes
您可以执行此操作,但必须使用Python Shell。 换句话说,用于启动Python脚本的外壳程序必须是Python进程。 然后,所有全局变量或类将一直存在,直到您关闭外壳程序为止。
查看cmd模块,该模块使编写Shell程序变得容易。 您甚至可以进行安排,以使未在Shell中实现的所有命令都传递给系统Shell进行执行(无需关闭Shell)。 然后,您将必须实现某种命令,例如prun,该命令通过使用runpy模块运行Python脚本。
[http://docs.python.org/library/runpy.html]
您将需要使用init_globals参数将特殊数据传递到程序的名称空间,最好是dict或单个类实例。
Michael Dillon answered 2020-02-04T05:27:22Z
0 votes
您可以通过os在服务器上运行一个持久脚本,该os加载/计算,甚至定期将sql数据重新加载/重新计算到某种内存结构中,然后通过套接字从其他脚本获取内存中的数据。
Stephen answered 2020-02-04T05:27:43Z