processEvents ブロックへの呼び出しが最大 9 秒間何もしないのはなぜですか?
私は PySide ベースの QT インターフェースを備えたアプリケーションを持っています。ここでは、UI コードが下位レベルの実際のアプリケーション ロジックの上に分離されたレイヤーとして配置されています。ユーザーが、しばらく実行される可能性のある低レベルのアプリケーション ロジックを実行するアクションを実行すると、実質的に次のことが起こります。
- GUI スレッドに直接進行状況ダイアログが表示されます。
- GUI スレッドで直接、下位レベルのロジックがワーカー スレッドを開始します。
- GUI スレッドで直接、下位レベルのロジックが進行状況ダイアログの更新 (間接的/分離) と QtGui.qApp.processEvents() を介したアプリケーション イベント キューのティック (再び間接的/分離) をループします。
- ワーカー スレッドでは、イベントに反応して QT 関数が (再び間接的/分離されて) 呼び出されます。これらはスロット/シグナルを介して GUI スレッドで発生し、GUI スレッドが (前述のように) processEvents() を呼び出すと実行されます。
- GUI スレッドで直接、ループが終了する前に、最後の processEvents() 呼び出しが約 9 秒間ブロックされます。これは、ワーカー スレッドのすべてのロジックが終了し、シグナル/スロット呼び出しを介して実行を待機している関数がなくなった後です。この通話では、アプリケーションに関連することは何も行われていません。そこで何をしているの?なぜブロックされているのですか?300 ミリ秒の最大処理時間を渡して、それが終了するかどうかを確認しようとしましたが、これは違いはありません。必要な限り、通話はロックされます。
- 進行状況ダイアログが閉じ、ユーザーはフォーカスを取り戻します。
これはすべて、分離された方法で実装された多くのファイルに分散されています。フローの図を示すためにスニペットを提供しようとします。
分離された下位レベルのロジック ワーカー ループ:
while not completed_event.wait(0.1) and not work_state.is_cancelled():
work_completeness, work_description = work_state.get_completeness(), work_state.get_description()
for client in self.clients:
if work_completeness != last_completeness or work_description != last_description:
client.event_prolonged_action_update(client is acting_client, work_description, step_count * work_completeness)
# THE LAST CALL TO THE NEXT LINE LOCKS UP FOR NO REASON
client.event_tick(client is acting_client)
last_completeness, last_description = work_completeness, work_description
PySide/QT レイヤー クライアントの event_tick 関数:
def event_tick(self, active_client):
# THIS IS WHERE THE LOCK UP HAPPENS
QtGui.qApp.processEvents()
PySide/QT レイヤーでシグナル/スロットを使用して、GUI スレッドで発生するワーカー スレッド呼び出しを取得します。
def event_pre_line_change(self, active_client, line0, line_count):
self.pre_line_change_signal.emit((line0, line_count))
def event_post_line_change(self, active_client, line0, line_count):
self.post_line_change_signal.emit((line0, line_count))
def event_uncertain_reference_modification(self, active_client, data_type_from, data_type_to, address, length):
self.uncertain_reference_modification_signal.emit((data_type_from, data_type_to, address, length))
ワーカー スレッドでの呼び出しをシグナル/スロットを使用して GUI スレッドに委譲する理由は、UI を更新することを考えると、これが PySide/QT に必要なものだからです。
より深く掘り下げたい場合の再現ケース: