この質問に対する補足として: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はcloud
LGPL の下で 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 の良さは言い尽くせません。私はそこで働いてもいませんでした。