4

TL;DR; - setuptools/distutils スクリプト ラッパー .exe entry_points は、Windows マルチプロセッシングの無限再帰をトリガーしません。Wheel のラッパー .exe entry_points が行います。以前の動作を取得するにはどうすればよいですか?

私たちの多くは、Python 2.X のマルチプロセッシング モジュールと Windows で、モジュール スクリプトを直接呼び出すときに無限再帰の問題に遭遇したことがあるでしょう。

マルチプロセッシングを使用する関数につながるライブラリのエントリ ポイントを作成したとき、エントリ ポイント スクリプトとそのラッピング .exe ファイルは、setuptools を使用してインストールしたときに Windows 上で実行可能であり、マルチプロセッシングを呼び出す関数を直接実行できました。およびプロセス オブジェクト。私のライブラリはマルチプロセッシングに依存して恥ずべき並列プログラムを高速化していたので、これは素晴らしいことでした。

bdist_wheel を使用してライブラリを共有するまでは、うまく機能していました。以前は、ビルド プロセスで .exe ラッパーとスクリプトが外側に追加されていましたが、.exe は同じ種類のラッパーではありませんでした。

私のバイナリ ファイル形式のスキルは決して優れたものではありませんが、zip 圧縮ファイルから実行可能ファイルへの何らかの変換があることを知っていたので、唯一の論理的なことを行って .exe ファイルを解凍しました。私のmingw bashシェルでさえzip / unzipを持っていなかったので、私は7zipを使いました。Wheel ファイルからインストールされた .exe ラッパーは、単純なメイン.py スクリプトを含むディレクトリに解凍されます。

# -*- coding: utf-8 -*-
import re
import sys

from example_multiprocessing.runner import main

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

それは、zip ファイルから実行された単なる Python スクリプトでした。爆発したのも不思議ではありません。

setup.py を使用して再インストールし、古いラッパー .exe を追加して、それを解凍しようとしました。見よ、7zipによって独自のファイルに抽出された.data、.pdata、.rdata、および.textセクションを含む完全なPortable Executableファイルです。2 時間後、distutils と setuptools のソース コードを調べて何が起こっているのかを調べたところ、表示されている .exe は、事前に作成されたランチャー exe にエントリ ポイント固有の Python コードを流し込むことによって作成されていることがわかりました。 Windows用。偉大な。私は以前よりも多くのことを知っています。しかし、違いが .exe ラッパーだった場合、なぜ -script.py entry_point が機能するのでしょうか?

__requires__ = 'example-multiprocessing==1.0.2'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('example-multiprocessing==1.0.2', 'console_scripts', 'example-mp-run')()
    )

load_entry_point特別ですか?EntryPoint.load() のラッパーであり、明示的に呼び出すために使用されます__import__

# From [https://bitbucket.org/pypa/pkg_resources/src/33e56f318f5086158de8bb2827acb55db2dbc153/pkg_resources.py?at=default#cl-2258][1]
def load(self, require=True, env=None, installer=None):
    if require: self.require(env, installer)
    entry = __import__(self.module_name, globals(),globals(), ['__name__'])
    for attr in self.attrs:
        try:
            entry = getattr(entry,attr)
        except AttributeError:
            raise ImportError("%r has no %r attribute" % (entry,attr))
    return entry

globals()ドキュメントからは行き止まりのように見えます__import__が、['__name__']便利なようです。問題は、それが組み込みであり、C で実装されていることです。GitHub__import__に投稿されたミラーを読み取ろうとしましたが、現時点では私の範囲を超えており、3 つ以上の相互作用する関数に分岐しています。追跡せず、fromlist との接続を維持します。に格納されているモジュールの属性にアクセスしようとした後の次のブロックに気を取られている可能性もあります。これは、エントリ ポイント関数自体であると推測されます。__import__entry

次のコードを実行すると:

getattr(__import__("example_multiprocessing.runner", globals(), globals(), ["__name__"]), "main")()

実行すると予想していたメイン関数が表示され、問題なく戻ります。

スクリプトの を含まないものに設定して、本当に__import__必要な作業を行っていますか? -m の背後にある機械がなぜランピーにならないのですか?__name____main__

4

0 に答える 0