13

StackOverflow に関する多くの推奨事項 (dill、cloudpickle など) に従って、依存関係を持つ Python 関数をピクルする複数のアプローチを試しましたが、すべてが私が理解できない根本的な問題に遭遇しているようです。

インポートされたモジュールから関数をピクルしようとするメイン モジュールがあり、それを ssh 経由で送信してピクルを解除し、リモート マシンで実行します。

したがって、メインは次のとおりです。

    import dill (for example)
    import modulea

    serial=dill.dumps( modulea.func )
    send (serial)

リモート マシンで次の操作を行います。

        import dill
        receive serial
        funcremote = dill.loads( serial )
        funcremote()

pickle されて送信される関数が main 自体で定義されたトップレベルの関数である場合、すべてが機能します。それらがインポートされたモジュールにある場合、ロード機能は「module modulea not found」タイプのメッセージで失敗します。

モジュール名が関数名とともにピクルされているようです。ピクルスを「修正」して依存関係を削除する方法、またはレシーバーにダミーモジュールを作成してピクル解除の受信者にする方法がわかりません。

どんなポインタでも大歓迎です。

--プラサンナ

4

1 に答える 1

17

私はdill著者です。私はこれとまったく同じことを繰り返しsshますが、成功しています。現在、dill他のシリアライザーは参照によってモジュールをピクルしています...そのため、ファイルで定義された関数を正常に渡すには、関連するモジュールが他のマシンにもインストールされていることを確認する必要があります。モジュールを直接 (つまり、参照によってではなく) シリアル化するオブジェクト シリアライザーはないと思います。

そうは言っても、dillオブジェクトの依存関係をシリアル化するためのオプションがいくつかあります。たとえば、クラス インスタンスの場合、デフォルトでdillはクラス インスタンスを参照によってシリアル化しないため、クラス定義もシリアル化してインスタンスと一緒に送信できます。ではdill、(非常に新しい機能を使用して) ファイルをシリアル化することによって、参照によって行うのではなく、ファイル ハンドルをシリアル化することもできます。しかし、繰り返しますが、モジュールで定義された関数のケースがある場合、モジュールはかなり普遍的に参照によってシリアル化されるため、運が悪いです。

dillただし、オブジェクトをピクルするだけでなく、ソースを抽出してソースコードを送信することで、これを行うことができる場合があります。pathos.ppおよびではpyina、オブジェクト (関数を含む)のソース依存関係dillを抽出し、それらを別のコンピューター/プロセス/などに渡していました。ただし、これは簡単なことではないため、ソース コードの代わりに関連するインポートを抽出して送信するというフェールオーバーを使用することもできます。dill

うまくいけば、これは面倒なことです (以下で抽出している関数の依存関係の 1 つに示されているように)。ただし、あなたが求めていることは、pathosssh トンネル化されたポートを介してコードと依存関係をさまざまなマシンに渡すために、パッケージで正常に実行されます。

>>> import dill
>>> 
>>> print dill.source.importable(dill.source.importable)
from dill.source import importable
>>> print dill.source.importable(dill.source.importable, source=True)
def _closuredsource(func, alias=''):
    """get source code for closured objects; return a dict of 'name'
    and 'code blocks'"""
    #FIXME: this entire function is a messy messy HACK
    #      - pollutes global namespace
    #      - fails if name of freevars are reused
    #      - can unnecessarily duplicate function code
    from dill.detect import freevars
    free_vars = freevars(func)
    func_vars = {}
    # split into 'funcs' and 'non-funcs'
    for name,obj in list(free_vars.items()):
        if not isfunction(obj):
            # get source for 'non-funcs'
            free_vars[name] = getsource(obj, force=True, alias=name)
            continue
        # get source for 'funcs'

#…snip… …snip… …snip… …snip… …snip… 

            # get source code of objects referred to by obj in global scope
            from dill.detect import globalvars
            obj = globalvars(obj) #XXX: don't worry about alias?
            obj = list(getsource(_obj,name,force=True) for (name,_obj) in obj.items())
            obj = '\n'.join(obj) if obj else ''
            # combine all referred-to source (global then enclosing)
            if not obj: return src
            if not src: return obj
            return obj + src
        except:
            if tried_import: raise
            tried_source = True
            source = not source
    # should never get here
    return

メソッドを中心に何かを構築することもできると思いdill.detect.parentsます。これは、特定のオブジェクトのすべての親オブジェクトへのポインターのリストを提供します…そして、関数のすべての依存関係をオブジェクトとして再構築できます…しかし、これは実装されていません。

ところで: ssh トンネルを確立するには、次のようにします。

>>> t = pathos.Tunnel.Tunnel()
>>> t.connect('login.university.edu')
39322
>>> t  
Tunnel('-q -N -L39322:login.university.edu:45075 login.university.edu')

ZMQ次に、、、、またはssh何でも使用して、ローカルポート全体で作業できます。でそうしたい場合はsshpathosそれも組み込まれています。

于 2014-10-15T22:25:25.913 に答える