1

Linux ボックスで Python 3 を使用し、同じホストに対して従来の rpyc を使用しています。現在のディレクトリに単純な python ファイル tst.py があり、その中に次の 2 行があります。

a = {'a': 0}

b = 3

次に、次のコマンドを実行します。

>>> import rpyc; conn = rpyc.classic.connect('127.0.0.1')
>>> conn.execute('import tst')
>>> conn.eval('dir(tst)')
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
    '__package__', '__spec__', 'a', 'b']
>>> conn.eval('tst.a, tst.b')
({'a': 0, 'b': 1}, 3)

すべてが期待どおりです。ここで接続を閉じる場合:「conn.close()」、python セッションを閉じ、現在のディレクトリから「pycache」を削除し、「tst.py」ファイルを編集して、1 行だけ残します。

a = {'a': 0, 'b': 2}

新しいセッションで上記の同じコマンドを最初から繰り返します。

……(飛ばして)……

>>> conn.eval('dir(tst)')
'__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
   '__package__', '__spec__', 'a', 'b']

>>> conn.eval('tst.a, tst.b')
({'a': 0, 'b': 1}, 3)

したがって、驚くべきことに、tst.py ファイルが変更され、ローカルの python キャッシュが削除されても、結果は同じままです。誰かが初心者に、私が間違ったことをしたことと、以前にロードされたコードをきれいにする方法を説明できますか? 「rpyc」には独自のキャッシュがありますか? この「tst.py」ファイルの名前を変更し、新しい名前で同じ手順をもう一度繰り返すと、正しい結果が得られます。繰り返しますが、これはキャッシュを指していますが、現在のディレクトリではありません。

4

1 に答える 1

0

を実行rpycしている場合は、1 つのサーバー プロセス (接続しているが、質問には表示されていません) と 1 つのクライアント プロセス (ここでは REPL を使用したようです) があることを意味します。

サーバーは、接続する前から、接続を閉じた後も実行を続けます。それがサーバーの役割です。問題は、サーバー プロセスの現在のメモリに存在する Python オブジェクトが表示されることです。

rpycにはキャッシュがありません。同じプロセスに 2 回接続しただけなので、1 回目よりも 2 回目に同じ結果が表示されました。
ファイルの名前を変更した場合は、tst.py再度インポートする必要がありますが、新しい名前を使用します。importモジュールを ing するときに Python が行うことは、moduleオブジェクトを作成してそれをユーザーに渡すことです。

conn.eval('dir(tst)')

モジュールのコンテンツを一覧表示するように Python に要求していdirます。これは、対応するファイルがインポートされたときに定義されたものです (そのコンテンツに対して行ったその後の変更を含む)。
サーバー プロセスに 2 回目に接続するとdir、まったく同じ Python モジュール オブジェクトのコンテンツがサーバー プロセスのメモリに存在するため、まったく同じ結果が得られます。

ただし、ファイル名を変更してインポートすると、最初のものとは異なる可能性がある 2 番目のモジュール オブジェクトが作成されます。

「Python セッションを閉じる」とは、クライアント プロセスを終了することを意味しますが、サーバー プロセスには影響しません。

フォルダーは、Python が中間コンパイル オブジェクトを配置するための__pycache__単なる場所であり、ファイルを再度インポートするのに必要な時間を短縮します。通常は無視してかまいません。いずれにせよ、それはあなたの現在の問題とは何の関係もありません。

解決策について話すには、何を達成しようとしているのかを知ることが役に立ちます。しかし、私はいくつかの一般的な答えを提供します:

  1. サーバー プロセスを停止してから再度開始すると、モジュール (ソース ファイルの内容を変更したもの) をインポートできます。サーバーを再起動する余裕がある場合はrpyc、このソリューションをお勧めします。他のソリューションに比べて一般的に簡単だからです。
  2. 単純にセッターを使用します: モジュール関数で定義してtst変数値を変更し、それらをリモート呼び出します。例 :
    >>> import rpyc; conn = rpyc.classic.connect('127.0.0.1')
    >>> conn.execute('import tst')
    >>> conn.eval('dir(tst)')
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
        '__package__', '__spec__', 'a', 'b']
    >>> conn.eval('tst.a, tst.b')
    ({'a': 0, 'b': 1}, 3)
    >>> conn.eval('tst.set_a(4)')
    >>> conn.eval('tst.a, tst.b')
    (4, 3)
    
    リセットする必要があるすべてを処理する必要があり、リセットが行われたこと、およびいくつかの変数を更新する必要があることをサーバーの一部に通知する必要がある可能性があります。前の回答よりも難しいですが、サーバー プロセスを再起動する必要はありません。
  3. を使用importlib.reloadして、Python に同じ名前の新しいモジュール オブジェクトを強制的に作成させることができます。これにより、ソース ファイルの内容に対する最近の変更が考慮されます。ただし、古いモジュールへの参照がまだ存在する可能性があるため、これによりNASTY問題が発生する可能性があります。そのため、両方のコンテンツ (リロード前のものとリロード後のもの) がアプリケーションのさまざまな部分に共存し、多くの紛らわしいバグが発生し、調査。私はそれをすることをお勧めしません。
于 2021-06-08T12:51:11.427 に答える