Pythonによるネイティブ実行ファイル

GraalPyは、GraalPyを使用するJavaアプリケーションのネイティブバイナリを生成するために、GraalVM Native Imageをサポートしています。

クイックスタート #

Mavenアーキタイプから開始した場合、生成された *pom.xml* により、Native Imageビルド用Mavenプラグインを使用してネイティブ実行ファイルを簡単に生成できます。

アプリケーションをビルドするには、以下を実行します。

mvn -Pnative package

このコマンドは、プロジェクトをパッケージ化し、ネイティブ実行ファイルを作成します。

生成されたファイル *pom.xml* と *Main.java* を見てください。これらのファイルには、Pythonリソースが結果のバイナリにどのように含まれるかが説明されています。生成されたプロジェクトは、出発点と見なす必要があります。Python標準ライブラリ全体が含まれているため、Pythonコードはすべての標準ライブラリコードを呼び出すことができます。リソースを手動で整理して、必要な量のPythonライブラリに削減することで、パッケージのサイズと起動時間を短縮できます。このJavaの例では、Pythonコンテキストに役立つデフォルトオプションをいくつか示していますが、Pythonコードで実行できることをさらに制御するために、他の設定が望ましい場合があります。

バイナリサイズの削減 #

Pythonは大規模な言語です。「バッテリー同梱」は、長い間CPythonの中心的な信条でした。互換性のある代替手段として、GraalPyもこれらの「バッテリー」のほとんどを含んでいます。これにより、JavaアプリケーションにGraalPyを含めると、バイナリサイズが大幅に増加する可能性があります。

開発者であるあなただけが、特定の埋め込みシナリオを知っています。デフォルトでは、特定のアプリケーションに必要な量よりもはるかに多くのものが含まれている場合があります。Javaに埋め込まれたPythonアプリケーションは、通常、完全なGraalPyディストリビューションよりもPythonインタープリターのユースケースが限られており、多くの場合、特定の機能が必要かどうかを事前に知ることができます。一部の機能(たとえば、暗号化アルゴリズムやソケットアクセス)は、場合によっては含めない方がよいこともあります。したがって、GraalPyをJavaアプリケーションに埋め込む場合、Python言語のコンポーネントを除外することで、バイナリサイズを削減し、セキュリティを向上させることができます。

Pythonコンポーネントの除外 #

GraalPyは、`native-image`コマンドラインで渡して言語の側面を除外できるいくつかのシステムプロパティを定義しています。これらのオプションを組み合わせると、実行ファイルのサイズを約20%削減できます。これらは以下のとおりです。

  • `python.WithoutSSL=true` - このオプションは、`ssl`モジュールを削除します。セキュアなネットワークアクセスまたは証明書のチェックが必要ない場合、これはJavaのSSLクラスとBouncyCastleライブラリを削除します。
  • `python.WithoutDigest=true` - このオプションは、`_md5`、`_sha1`、`_sha256`、`_sha512`、`_sha3`、および`_hashlib`モジュールを削除します。これにより、GraalPyから`java.security.MessageDigest`および`javax.crypto.Mac`の直接使用が削除されます。
  • `python.WithoutPlatformAccess=true` - これにより、`signal`および`subprocess`モジュールが削除され、Unix UIDやGIDなどのプロセ spropertyへのアクセス、またはJavaのデフォルトタイムゾーンの設定が削除されます。これはバイナリサイズに大きな影響を与えませんが、これらがコンテキストオプションで動的に無効にされる不要な機能である場合、事前に削除することもできます。
  • `python.WithoutCompressionLibraries=true` - これにより、`zlib`、`lzma`、`bzip2`、および`zipimporter`モジュールと関連クラスが削除されます。これらのモジュールには、ネイティブ実装と純粋なJava実装の両方があります(前者はパフォーマンスのため、後者はより良いサンドボックス化のため)。ただし、必要ない場合は完全に削除できます。
  • `python.WithoutNativePosix=true` - デフォルトの`os`モジュールバックエンドは、GraalPyがランチャーではなく埋め込みで実行される場合、純粋なJava実装です。GraalPyのネイティブPOSIXバックエンドは、CPythonのPOSIXインターフェースと100%互換性がある場合にのみ推奨され、使用しない場合は、このオプションを使用してビルドから削除できます。
  • `python.WithoutJavaInet=true` - Pythonの`socket`モジュールのJava実装は、Javaのネットワーキングクラスに基づいています。埋め込みシナリオでネットワークアクセスが拒否されている場合、このオプションはバイナリサイズをさらに削減できます。
  • `python.AutomaticAsyncActions=false` - シグナル処理、Pythonの弱参照コールバック、およびネイティブリソースのクリーンアップは、通常、Pythonメインスレッドにセーフポイントアクションを送信するGraalPyデーモンスレッドを生成することによって自動的に実行されます。これは、スレッドプールを持つ`ExecutorService`を使用します。このような追加のスレッドを許可しない場合、または`ExecutorService`と関連クラスのプルインを回避する場合は、このプロパティを`false`に設定し、コンテキストのポリグロットバインディングから`PollPythonAsyncActions`オブジェクトを取得します。このオブジェクトは実行可能であり、目的の場所でPythonの非同期アクションをトリガーするために使用できます。
  • `python.WithoutJNI=true` - このオプションは、JNIを使用するすべてのコードを削除します。結果として、HPy JNIバックエンドや、JNIに依存する他の部分を使用することはできません。

事前初期化されたPythonヒープの削除 #

ネイティブ実行ファイルのサイズを削減するもう1つの便利なオプションは、実行ファイルから事前初期化されたPythonコンテキストを省略することです。デフォルトでは、デフォルトのPythonコンテキストは既に事前初期化されており、すぐに実行できます。これにより、起動がわずかに改善されますが、バイナリに数千のPythonオブジェクトが含まれることになります。コンテキストの共有を許可するためにカスタムポリグロットエンジンを使用する埋め込みアプリケーションでは、事前初期化されたコンテキストはまったく使用できず、これらのオブジェクトを含めると無駄になります。事前初期化されたヒープは、`native-image`コマンドに以下を渡すことで省略できます。

-Dimage-build-time.PreinitializeContexts=

Pythonコードのランタイムコンパイルの無効化 #

バイナリサイズが実行速度よりも znacznie重要である場合(すべてのPythonスクリプトが短時間実行、大量のI / Oを実行、またはスクリプトが複数回実行されることがめったにない場合)、JITコンパイルを完全に無効にするのは理にかなっています。これはPythonのパフォーマンスに大きな影響を与える可能性があるため、このオプションを使用する場合は、実際のユースケースのランタイム動作をテストしてください。これは、次のオプションを渡すことで実現できます。

-Dtruffle.TruffleRuntime=com.oracle.truffle.api.impl.DefaultTruffleRuntime \
-Dpolyglot.engine.WarnInterpreterOnly=false

まとめ #

これらのアプローチをすべて組み合わせることで、GraalPyバイナリのサイズを半分にすることができます。埋め込みアプリケーションはそれぞれ異なり、残りのJavaコードによってプルインされるコードも重要であるため、これらのオプションの組み合わせを試して、特定のインスタンスでどのような効果があるかを判断する必要があります。

Pythonパッケージの出荷 #

デフォルトでは、Mavenアーキタイプは、必要なすべてのPythonファイルをネイティブバイナリ自体に含めるように設定されているため、イメージは自己完結型です。

カスタム埋め込みでは、Python標準ライブラリはネイティブイメージの横にコピーされます。ネイティブイメージを移動するときは、標準ライブラリフォルダーをその横に置いておく必要があります。

お問い合わせ