Python 関数とその依存関係を pickle 化するにはどうすればよいでしょうか? 質問する

Python 関数とその依存関係を pickle 化するにはどうすればよいでしょうか? 質問する

この質問に対する補足として:Python 関数を pickle 化する (またはコードをシリアル化する) 簡単な方法はありますか?

上記の投稿からこの箇条書きの例を見たいと思います。

「関数が取得する必要のあるグローバル (インポートされたモジュール、他の関数などを含む) を参照する場合、これらもシリアル化するか、リモート側で再作成する必要があります。私の例では、リモート プロセスのグローバル名前空間を指定しているだけです。」

marshal を使用して関数のバイト コードをファイルに書き込む簡単なテストを実行しています。

def g(self,blah): 
    print blah

def f(self):
    for i in range(1,5):
        print 'some function f'
        g('some string used by g')

data = marshal.dumps(f.func_code)

file = open('/tmp/f2.txt', 'w')
file.write(data)

次に、新しい Python インスタンスを起動して、次の操作を実行します。

file = open('/tmp/f2.txt', 'r')
code = marshal.loads(file.read())
func2 = types.FunctionType(code, globals(), "some_func_name");
func2('blah')

その結果、次のようになります。

NameError: global name 'g' is not defined

これは、g を含めるために私が行ったさまざまなアプローチとは無関係です。基本的に同じアプローチで g を f として送信しようとしましたが、f はまだ g を認識できません。受信プロセスで f が使用できるように、g をグローバル名前空間に取り込むにはどうすればよいですか?

これを行う方法の例として pyro を見ることを勧める人もいました。私はすでに disco プロジェクトの関連コードを理解しようと試みました。dPickle クラスを取得し、disco/tests/test_pickle.py 機能をスタンドアロン アプリで再現しようとしましたが、成功しませんでした。私の実験では、dumps 呼び出しによる関数のマーシャリングで問題が発生しました。とにかく、次は pyro の調査になるかもしれません。

要約すると、私が求めている基本的な機能は、ネットワーク経由でメソッドを送信し、それとともにすべての基本的な「ワークスペース」メソッド (g など) を送信できることです。

回答からの変更点の例:

動作中のfunction_writer:

import marshal, types

def g(blah): 
    print blah


def f():
    for i in range(1,5):
        print 'some function f'
        g('blah string used by g')


f_data = marshal.dumps(f.func_code)
g_data = marshal.dumps(g.func_code);

f_file = open('/tmp/f.txt', 'w')
f_file.write(f_data)

g_file = open('/tmp/g.txt', 'w')
g_file.write(g_data)

動作中のfunction_reader:

import marshal, types

f_file = open('/tmp/f.txt', 'r')
g_file = open('/tmp/g.txt', 'r')

f_code = marshal.loads(f_file.read())
g_code = marshal.loads(g_file.read())

f = types.FunctionType(f_code, globals(), 'f');
g = types.FunctionType(g_code, globals(), 'g');

f()

ベストアンサー1

2020年9月更新:下記の @ogrisel のコメントを参照してください。PiCloud の開発者は、私がこの回答のオリジナル バージョンを 2013 年に書いた直後に Dropbox に移行しましたが、7 年経った今でも多くの人が cloudpickle モジュールを使用しています。このモジュールは Apache Spark に移行し、そこでメンテナンスと改善が続けられています。それに応じて、以下の例と背景テキストを更新しています。

クラウドピクル

クラウドピクルパッケージは、関数、メソッド、クラス、さらにはラムダや依存関係を pickle 化できます。試してみるには、pip install cloudpickle次のようにします。

import cloudpickle

def foo(x):
    return x*3

def bar(z):
    return foo(z)+1

x = cloudpickle.dumps(bar)
del foo
del bar

import pickle

f = pickle.loads(x)
print(f(3))  # displays "10"

つまり、を使用するのcloudpickle.dump()cloudpickle.dumps()同じ方法で またはを呼び出しpickle.*、その後、ネイティブのpickle.load()またはを使用してpickle.loads()解凍します。

背景

PiCcloud.comはcloudLGPL の下で python パッケージをリリースし、他のオープンソース プロジェクトがすぐにそれを使い始めました (cloudpickle.pyいくつか見るには Google で検索してください)。picloud.com の人々は、汎用コード ピクルを機能させるために努力する動機がありました。彼らのビジネス全体がそれを中心に構築されていたのです。アイデアは、cpu_intensive_function()それを Amazon の EC2 グリッドで実行したい場合は、次のものを置き換えるだけでよいというものでした。

cpu_intensive_function(some, args) 

と:

cloud.call(cpu_intensive_function, some, args)

後者は、cloudpickle依存するコードとデータを抽出し、EC2 に送信して実行し、呼び出したときに結果を返していましたcloud.result()

Picloud はミリ秒単位で課金され、非常に安価でした。数百の CPU コアをそれぞれ数秒ずつ必要とするときに、モンテ カルロ シミュレーションや金融時系列分析によく使用していました。何年も経った今でも、Picloud の良さは言い尽くせません。私はそこで働いてもいませんでした。

おすすめ記事