AKAGI Rails

鉄道模型シミュレーターで遊んでいたはずが、気づいたらPythonなども。

VRMNXpyでマルチスレッド

<注意: VRM NXは開発途上の段階であり,βテストの経過に伴って仕様変更の可能性がある。本エントリに示す情報は執筆時点でのものである。> (2019/1/23 現在 Ver. 6.0.0.25)

Pythonではthreadingモジュールを使用することでマルチスレッド処理を行うことができます。VRMNXビュワーでもマルチスレッド処理ができれば,ちょっとしたタイマー処理を,VRMNXシステムのイベントハンドラを経由せずに行うことができるので,自動運転などのアドオン組み込みが楽になります。

VRMNXβテスト 公式ドキュメントの制限事項にも, Python付属のLIBの使用については、VRMNXではサポートしていません。importしても問題ないか確認いないため、サポート外としてご利用ください とあるとおり,threadingを含むモジュールの使用はサポート外となるわけですが,リリースノート6.0.0.25スレッドを生成する場合は、レイアウトにFrameイベントが発生するようにしてください。 FrameイベントによってPythonインタープリタを駆動します とも書いてあります。動けば御の字,動かなかったら諦めてね,というお気持ちなんでしょうか。

このあたりを参考に,サンプルとして,キーを押すと1秒おきに'Hello, World!'を5回表示する処理を組んでみます。

まずは,使用するモジュールをimportして,リリースノートにあったようにレイアウトにFrameイベントを設定します。これをしないとあまり思ったように動きません。
(いろいろやってみたところ,どうやら,vrmapiの命令は,VRMNXシステムのメインスレッドと別のスレッドから実行しても,メインスレッドのPythonエンジンが何らかのイベント発生によって駆動されるまで実行待ち状態になるらしい。)

import vrmapi
import threading, time
vrmapi.LAYOUT().SetEventFrame()

Hello, Worldを1秒おきに5回表示する関数は次のようです。timeモジュールのsleep関数をここで使います。何もしない待ち時間を作る関数です。

import time
def hello5():
    for i in range(5):
        vrmapi.LOG('Hello, World!')
        time.sleep(1.0)

これを,キーイベントをきっかけに,別スレッドを立ち上げて実行します。

# レイアウト
def vrmevent(obj, ev, param):
    if ev == 'init':
        obj.SetEventKeyDown('A')
    elif ev == 'keydown':
        if param['keycode'] == 'A':
            th = threading.Thread(target = hello5)  # スレッドを定義
            th.start()        # スレッドをスタート
            vrmapi.LOG('threadをstartしました')

スレッドを定義するところでは,新しいスレッドで実行する関数をtarget属性に指定します。関数名だけ書けばOKで,カッコとか引用符は不要です。

threadingモジュールにはTimerオブジェクトもありますが,VRMスクリプトで言うところのAfterイベントのように,一定時間後の1回きりの処理を設定できます。

予告していた,マルチスレッドで遮断機の遅延作動を組み込んだ踏切は,次回に持ち越します。しばしお待ちを。