| On this page |
このクラスは、コンテキストマネージャであり、ユーザが ⎋ Escを押すことで長時間実行されている処理を中断できるようにするほか、メインウィンドウ下部のステータスラインに進捗状況のパーセンテージを表示することもできます。
このクラスは、長時間実行される可能性のあるPythonノード(Python SOPなど)やシェルフスクリプトで使用してください。
例えば、入力ジオメトリのすべてのポイントをループ処理するコードがあった場合、ジオメトリに数百万のポイントがあると、その処理に長い時間がかかる可能性があります。
ユーザがその処理を中断できるようにし、進捗状況を表示できるようにするには、その処理をhou.InterruptableOperationブロック内で実行してください。
重要 :スクリプト側でユーザが
⎋ Escを押したかどうかをチェックするのは、コンテキストオブジェクトのupdateProgress()メソッドをコールした時 のみ です。
そのため、ブロック内にupdateProgress()コールを追加する必要があります。
通常は、ループの各反復の開始時にコールします(進捗状況の割合を指定しない場合でも同様です)。
(updateProgress()をコールすることで、Houdiniがイベントに応答できるようになり、オペレーティングシステムに対して応答なしの状態に見えなくなります。例えば、定期的にupdateProgress()をコールすることで、MacOSで“ビーチボール”カーソルが表示されないようにすることができます。)
ユーザが操作を中断した場合、コンテキストブロックはhou.OperationInterrupted例外を発生させて終了します。 とはいえ、スクリプト内でこの例外をキャッチしたくない場合があります。
-
シェルフツール内で
hou.OperationInterrupted例外をキャッチしない場合、ツールスクリプトは単に停止し、Houdiniはユーザに例外を表示しません。スクリプトにクリーンアップ処理が必要ない場合、通常ではこれがユーザの期待する動作です。 -
Pythonノード(Python SOPなど)内で例外をキャッチしない場合、Houdiniは自動でそのノードにエラーを表示します(エラーメッセージは
Cooking was interruptedとなります)。繰り返しになりますが、これはノードが長時間実行される操作が中断された場合の典型的な処理方法です。
このオブジェクト出力を試すには、シェルフツールを作成して、以下のコードをツールスクリプトに貼り付けてください:
import time import hou try: with hou.InterruptableOperation("Waiting around doing nothing") as iop: for i in range(100): # ここには実際の処理を記述しますが、今回は単にスリープ処理を入れます。 time.sleep(0.1) # ループや一連のステップ内で、コンテキストオブジェクトに対して # updateProgress()をコールして、中断の有無をチェックします。 # オプションで浮動小数点を渡すことで、ユーザに処理の進捗率を知らせることができます。 # (最初の引数は"percentage"となっていますが、実際には浮動小数点を受け取ります。) iop.updateProgress(i / 100) except hou.OperationInterrupted: # ユーザがEscキーを押しました(または、 # timeout_ms引数を使用した場合、処理がタイムアウトしました) hou.ui.displayMessage("Interrupted") else: # 処理は中断されることなく完了しました。 hou.ui.displayMessage("Completed")
入れ子処理 ¶
複数の中断可能な処理を入れ子にすることができます。 例:
# Start the overall, long operation. with hou.InterruptableOperation("Beginning operation", "Performing a Long Operation", open_interrupt_dialog=True) as iop: for i in range(num_tasks): # 全体の進捗状況を更新します。 operation.updateLongProgress(i / num_tasks) # サブ処理を開始します。 with hou.InterruptableOperation(f"Performing Task {i + 1}") as sub_iop: for j in range(num_subtasks): # サブ処理の進捗状況を更新します。 sub_iop.updateProgress(j / num_subtasks) # # ここでサブタスクを実行します。 #
タイムアウト処理 ¶
コンテキストオブジェクトの作成時にtimeout_ms引数を使用することで、処理に要する時間を制限することができます。
-
時間制限に達すると、ユーザが ⎋ Escを押した場合と同様に
hou.OperationInterruptedが発生します。 -
ユーザが ⎋ Escを押した場合と同様に、通常ではタイムアウトは
updateProgress()メソッドをコールした時にのみチェックされるので、ブロック内で定期的にそのメソッドをコールする必要があります。一部のHOM関数には内部で進捗状況を更新するものがあり、それもタイムアウトのチェックをトリガーする可能性があります。 例えば、
LopNode.stagePrimStats()コールを、タイムアウトありのhou.InterruptableOperationブロックで囲むと、stagePrimStats()が内部で処理中にHoudiniを更新するため、タイムアウトによってstagePrimStats()が中断されます。
例えば、この修正版のサンプルは通常10秒間実行されますが、timeout_ms=1000引数によって、1秒後にInterruptedと表示されます:
import time import hou try: with hou.InterruptableOperation("Waiting around doing nothing", timeout_ms=1000) as iop: for i in range(100): # ここには実際の処理を記述しますが、今回は単にスリープ処理を入れます。 time.sleep(0.1) iop.updateProgress(i / 100) except hou.OperationInterrupted: # ユーザがEscキーを押しました(または、 # timeout_ms引数を使用した場合、処理がタイムアウトしました) hou.ui.displayMessage("Interrupted") else: # 処理は中断されることなく完了しました。 hou.ui.displayMessage("Completed")
Tipsとメモ ¶
-
デフォルトでは、Houdiniはステータスラインに進捗状況をテキストのみで表示します。 オブジェクトの作成時に
open_interrupt_dialog=Trueを指定すると、Houdiniは進捗状況をプログレスバーで表示するダイアログを開きます。通常、処理に1~2秒以上かかる場合は、ダイアログを開くことを推奨します。 -
updateProgress()コールは短い時間で済むものの、それが積み重なって時間がかかってしまいます。ループが多い場合、例えば毎回の反復ではなく、10回に1回といった頻度でコールすることを推奨します。 -
hou.InterruptableOperationはPythonシェルでは動作しません。単に試したいだけであれば、シェルフツールを利用してください。 -
Houdiniは、ステータスバーにすべての進捗状況の更新を表示しない場合があります。パフォーマンス上の理由から、ステータスバーの更新は独自のスケジュールで行なわれます。
-
withステートメント外でこのオブジェクトを作成しようとすると、hou.OperationFailedが発生します。
メソッド ¶
__init__(operation_name, long_operation_name=None, open_interrupt_dialog=False, timeout_ms=0)
新しいInterruptableOperationを構築します。
operation_name
中断ダイアログの進捗バーに表示する中断可能な処理の説明。
long_operation_name
長くで高レベルな処理の説明。Noneでない場合、その長い処理名が中断ダイアログ上の2番目の進捗バーに表示されます。
open_interrupt_dialog
中断ダイアログを表示させるかどうか決めます。
timeout_ms
操作が自動で中断されるまでに許容される時間をミリ秒単位で指定する整数値。
このタイムアウトは、updateProgressまたはupdateLongProgressのメソッド(または、ネイティブのHoudiniメソッドを呼び出した時のC++相当のメソッド)を使用して進捗状況が更新された場合にのみチェックされます。
タイムアウトは“ネスト”させることはできません。
“外側”の処理に既にタイムアウトが設定されている状態で“内側”の処理にタイムアウトを設定しても、その設定は無視されます。
タイムアウトによって引き起こされた中断は、ユーザによって引き起こされた中断とまったく同様に扱われるため、ノードが中断エラー状態になる可能性があります。 この状況を回避したい場合は、タイムアウトが設定された中断可能な処理を開始する前に、データが必要となる可能性のあるノードをすべてクックするようにしてください。
updateLongProgress(percentage=-1.0, long_op_status=None)
長いまたは高レベルな処理の進捗パーセンテージとステータスを更新します。 同時に、その処理がユーザに中断されたかどうかチェックします。
percentage
名称とは異なりますが 、この引数には、 パーセンテージ ではなくて0.0から1.0までの 浮動小数点 を指定します。
この数値がマイナスの場合、Houdiniは進捗状況を表示しません。
long_op_status
長時間かかる処理の現在の状態を説明するテキスト(存在する場合)。 この引数に値を指定すると、中断ダイアログの2番目の進捗バーのテキストが上書きされます。
updateProgress(percentage=-1.0)
処理の進捗パーセンテージを更新します。同時に、その処理がユーザに中断されたかどうかチェックします。
percentage
名称とは異なりますが 、この引数には、 パーセンテージ ではなくて0.0から1.0までの 浮動小数点 を指定します。
この数値がマイナスの場合、Houdiniは進捗状況を表示しません。