web-dev-qa-db-ja.com

Python scriptの実行間で永続変数をメモリに保持する

結果変数をメモリに保持する方法はありますか?スクリプトの先頭を実行するたびに結果変数を再計算する必要はありませんか?スクリプトを実行するたびに、データセット(ディスクから読み取り中)に対して正確な操作の長い(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変数を開くためには永続オブジェクトのファイル名を指定する必要があるように見えると思いますそれが私が探しているものかどうかはわかりません。

私がやりたいことを棚上げにするためのヒントはありますか?代替案はありますか?

49

reloadグローバル関数を使用してメインスクリプトのコードを再実行すると、このようなことを実現できます。メインスクリプトをインポートし、キャッシュする変数を要求し、ラッパースクリプトのモジュールスコープ内でそのコピーをキャッシュするラッパースクリプトを記述する必要があります。 )、reload(yourscriptmodule)を呼び出しますが、今回はyourscriptが高価な計算をバイパスできるようにキャッシュされたオブジェクトを渡します。以下に簡単な例を示します。

wrapper.py

import sys
import mainscript

part1Cache = None
if __== "__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に対して新しいコードを実行できます。

42
Peter Lyons

将来のセッションのために1つのオブジェクト(またはオブジェクトグラフ)のみを保持したい場合、シェルブモジュールはおそらく過剰です。気になるオブジェクトをピクルスするだけです。 pickle-fileがない場合は作業を行い、pickleを保存します。pickle-fileがある場合はpickle-fileをロードします。

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
Matt Anderson

データをメモリに保持するには、プロセスを実行し続ける必要があります。メモリは、シェルではなく、スクリプトを実行するプロセスに属します。シェルはメモリを保持できません。

したがって、コードを変更し、プロセスを実行し続けたい場合は、変更されたモジュールをリロードする必要があります。メモリ内のデータのいずれかが変更されるクラスのインスタンスである場合、新しいクラスのインスタンスに変換する方法を見つける必要があります。それは少し混乱です。この種のホットパッチ適用が得意な言語はこれまでになく(Common LISPが思い浮かびます)、物事がうまくいかない可能性が多くあります。

6
Dietrich Epp

Pythonのシェルフは、ピクルス(シリアル化)オブジェクトの永続化ソリューションであり、ファイルベースです。利点は、Pythonオブジェクトを直接格納することです。つまり、APIは非常に単純です。

あなたが本当にディスクを避けたいなら、あなたが探している技術は「メモリ内データベース」です。いくつかの選択肢があります。これを参照してくださいSO質問: Pythonのメモリ内データベース

3
Ray Toal

これは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 。)変更を行うたびに実行します。

1
John

Osを介してサーバー上で永続スクリプトを実行し、sqlデータをある種のメモリ構造に定期的に再ロード/再計算してから、ソケットを介して他のスクリプトからメモリ内データにアクセスできます。

0
Stephen

これを行うことはできますが、Pythonシェルを使用する必要があります。言い換えると、Pythonスクリプトを開始するために使用するシェルは、Pythonプロセス。その後、シェルを閉じるまで、すべてのグローバル変数またはクラスが存続します。

シェルプログラムの作成を容易にするcmdモジュールを見てください。シェルに実装されていないコマンドがシステムシェルに渡されて実行されるようにすることもできます(シェルを閉じずに)。次に、prunモジュールを使用してPythonスクリプトを実行する何らかのコマンド、たとえばrunpyを実装する必要があります。

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

Init_globalsパラメーターを使用して、特別なデータをプログラムの名前空間、理想的にはdictまたは単一クラスのインスタンスに渡す必要があります。

0
Michael Dillon