長大なループをボタン操作などで停止させたい
- Google ColabなどのJupyter notebook上でボタン押下でループ処理を実行
- ループは一定時間(数)処理した後に自動終了する
- ただし状況で長時間(回数)になるケースがある
- ユーザー操作により途中で停止させたい
前提(環境)
Google Colab上で実装したい為、tkInterではなくipywidgetsを使って実装。
開始と停止ボタンをipywidgets.Button()で作成し、それぞれループ開始と停止の関数をバインド。
VSCode上のJupyter notebookでも確認したが同じ結果。
状況
開始ボタン押下でループを開始し、停止ボタンで終了用のフラグを立てるようにしています。
ループ中でフラグを監視し、フラグが立った所でループを終了させるようにしましたが停止しません。
ループが優先され、ボタン押下イベントが通知されていないと考えてループを別スレッドで実行するように変更してみました。
しかし、結果は同じでループは終了しません。「停止」ボタンでフラグを立てていますが、そもそもボタン押下時のイベントがループ中は保留されてしまうように見えます。
Threadの使い方が悪いのか、iwidgetsの使い方なのか判然としなく、手掛かりを頂けたらと思い投稿しました。
発生している問題・エラーメッセージ
停止ボタンを押下しても即反映されず、ループ終了後にイベントを受けて処理している様子です。
ループ中にイベントを受けていないので、ループが停止せずに最後まで到達してしまいます。
実行結果
Start Loop:0 Loop:1 Loop:2 Loop:3 Loop:4 Loop:5 Loop:6 Loop:7 Loop:8 Loop:9 not alive Stop Stop Stop Stop Stop
該当のソースコード
Python
1import time 2import ipywidgets as widgets 3 4from IPython.display import display 5import threading 6 7flag = False 8 9def loop_start(e): 10 print('Start') 11 thread = threading.Thread(target=count_loop) 12 thread.start() 13 14 try: 15 while True: 16 thread.join(timeout=0.1) 17 if not thread.is_alive(): 18 print('not alive') 19 return 20 if flag: 21 return 22 except KeyboardInterrupt: 23 print('Interrupt') 24 25def count_loop(): 26 for i in range(10): 27 if flag: 28 return 29 time.sleep(1) 30 current.value = str(i) 31 pass 32 33def loop_stop(e): 34 print('Stop') 35 flag = True 36 37output = widgets.Output() 38start = widgets.Button(description='開始') 39stop = widgets.Button(description='停止') 40buttons = widgets.Box([start, stop]) 41 42start.on_click(loop_start) 43stop.on_click(loop_stop) 44 45display(buttons, output)
試したこと
処理間隔などの問題でボタン押下イベントを受け付けていない可能性を考えて、ループ中にsleep()を挟んでみましたが変わりませんでした。
また、キーボードイベントでインターラプトできるとの事だったので仕込んでみましたが、Ctl+Cも効いているように見えません。
Google Colab環境、VSCode環境どちらでも同じ結果となりました。
補足情報(FW/ツールのバージョンなど)
Google Colaboratory(通常版)
VSCode 上のJupyter notebook(v2023.2.1000481019)
Python 3.10.7

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/02/17 06:54
2023/02/17 07:50