Embedded Pythonの使い所は?
Python流行ってますよね。(一時は圧倒的な支配力のあったJavaも、O社に買われてライセンスが云々とか言われ始めた頃からブレーキが掛かってしまった気がします。)
Pythonの魅力の一つがパッケージで様々な機能が提供されていることがあげられるかなと思っています。
私もこれまでPythonのコードをそこそこ書いてきました。実のところ、ここ1年では間違いなくObject ScriptよりPythonのほうが書いた量が多いです。Excelのドキュメントがそれらよりも遥かに多いのは何とかしたいところですが😅
IRISと連携するため$ZF(-1)を使ってPythonプログラムをコールしているものもあります。
IRIS 2021.2からPythonがIRISにEmbedded Pythonとして組み込まれたということで、どのように使えるかを試してみました。
なお、使用した環境は以下です。
OS: Linux Alma8 5.14.0-162.22.2.el9_1.x86_64 #1 SMP PREEMPT_DYNAMIC Mon Mar 27 07:34:40 EDT 2023 x86_64 x86_64 x86_64 GNU/Linux IRIS: IRIS for UNIX (Red Hat Enterprise Linux 9 for x86-64) 2022.1.2 (Build 574U) Fri Jan 13 2023 15:13:22 EST
■ まずはEmbedded Pythonを動かしてみる
パッケージのインストール
IRISの Embedded Pythonが使用するパッケージは、IRISインストールディレクトリの下の
$ pip3 install --target /irissys/mgr/python/ boto3 Collecting boto3 Downloading boto3-1.28.67-py3-none-any.whl (135 kB) |################################| 135 kB 3.4 MB/s Collecting botocore<1.32.0,>=1.31.67 Downloading botocore-1.31.67-py3-none-any.whl (11.3 MB) |################################| 11.3 MB 11.0 MB/s Collecting s3transfer<0.8.0,>=0.7.0 Downloading s3transfer-0.7.0-py3-none-any.whl (79 kB) |################################| 79 kB 8.1 MB/s (中略) Successfully installed boto3-1.28.67 botocore-1.31.67 jmespath-1.0.1 python-dateutil-2.8.2 s3transfer-0.7.0 six-1.16.0 urllib3-1.26.18
Embedded Pythonコードで書いてみる
/// Embedded Python で Mail 出す
ClassMethod EmbPyMail(Subject As %String, Body As %String) [ Language = python ]
{
import boto3
# 以下の値はダミーです
accesskey = "AKIAABCDEFGHIJKLMNOP"
secretkey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
topic_arn = "arn:aws:sns:ap-northeast-1:012345678901:SnsTopicName"
sns = boto3.resource("sns", aws_access_key_id=accesskey, aws_secret_access_key=secretkey, region_name="ap-northeast-1")
response = sns.Topic(topic_arn).publish(
Message=Body,
Subject=Subject
)
}.png)
.png)
■ Embedded Pythonを使うメリットとは?
同一プロセスで実行
この動画の1:02秒あたりを見ると、Embedded PythonはIRISと同一プロセスで動作するように見えます。
ということで、プロセスIDを表示するコードで確認してみます。
/// PIDを表示するだけ
ClassMethod WritePID() [ Language = python ]
{
import os
print(os.getpid())
}動かしてみると、確かに同じプロセスで動いているようです。
.png)
これと同様の処理を$ZF(-1)で実行すると別プロセスになります。
# /tmp/pid.py# PIDを表示するだけimport os
print(os.getpid()).png)
ということはEmbedded Pythonは、$ZF(-1)に比べてプロセス立ち上げる処理がなくなる分だけ高速に起動することが出来そうです。試してみましょう。
ClassMethod CallSpeed()
{
S times=1000W"$ZF(-1) Call: "S st=$ZH
F i=1:1:times D$ZF(-1,"python /tmp/exit.py")
W$ZH-st,"sec",!
W"Embedded Python Call: "S st=$ZH
F i=1:1:times D..PyReturn()
W$ZH-st,"sec",!
}
ClassMethod PyExit() [ Language = python ]
{
return
}# /tmp/exit.py# 抜けるだけ
exit.png)
Embedded Python のほうが400倍ぐらい早いですね。
とはいえ、1回の$ZF(-1)では0.02sec位ですから何度も呼び出すものでなければ$ZF(-1)でも良いと思います。
逆に何度も繰り返し呼ぶような処理であれば、Embedded Pythonを使うメリットがありそうです。
引数・戻り値の受け渡し
インプロセスで呼ばれることのメリットとしては、引数・戻り値を柔軟に受け渡せるということが考えられます。
$ZF(-1)では引数はコマンドの最大長に制限されます。Windows: 8kB, Linux: 大体2MB程度(ARG_MAX参照)であまり困ることはないですが、一時ファイルとかに書き出してファイルパスを渡す方法もよくやりますね。$ZF(-1)での戻り値はPythonコード中でexit(n)で設定するリターンコードnを得る方法がありますが数値しか渡せないため、それ以外の場合は結果ファイルを作ってIRISでそれを読むことでしのいでいます。
それがEmbedded Pythonでは自由に引数、戻り値(タプルでの複数値の返却も)を受け渡すことが出来ます。
ClassMethod ParamRev()
{
Set rev=..pyParamRev($H)
Write rev.GetAt(1),!,rev.GetAt(2) // GetAt(n)でタプル各要素にアクセス。要素数はCount()で
}
ClassMethod pyParamRev(horo) [ Language = python ]
{
print(horo)
n = 100s = "aaa"return n, s # 複数の値をタプルで返す
}.png)
その他の使い所は?
PythonコードからIRISデータ・グローバルにアクセスすることはありそうです。が、SQL経由やクラスメソッドで用意された機能を利用するならともかく、グローバルアクセスするならデータ構造の理解とかも必要になりますしObject Script使ったほうが良さそうな気がします。
あとは、IRISクラス定義の中に全ての処理をまとめておきたい場合でしょうか? 私はPythonコードはPythonコードで固めておきたい派なのですが、IRISのクラスと近いところに配置するメリットもありそうに思います。
■ まとめ
Embedded Python使うのはどんな時?は、以下のいくつかに該当する時なのかなと個人的に思います。
- 有用なPythonパッケージを使いたい
- 繰り返しPython処理を呼び出す
- 引数・戻り値が多い
- IRISクラス定義で全てのコードをまとめて書きたい
他に、こんなシチュエーションで使うと便利というものがありましたら、教えていただけると嬉しいです。
コードはこちらに配置しています。
#第1回 InterSystems Japan 技術文書ライティングコンテスト 最終日に滑り込み。