コードの問題点:
thread.is_alive() はメソッドなので呼び出しが必要です。
if thread.is_alive: は常に真になります。
裏でタイムアウトしたスレッドが生きていて気持ち悪いです。
スレッドが残っているのは正常な動作です。
thread.join(timeout=3) でのタイムアウトは、
呼び出し側で、スレッドの終了まで待機しているブロッキング状態の解除であって、
対象のスレッドが行っている処理には影響しません。
スレッドを安全に終了したい場合、中断処理は自分で実装する必要があります。
threadは殺すのは良くないということですが、解決方法を探しています。
Python 標準ライブラリ スレッドベースの並列処理
注釈 デーモンスレッドは終了時にいきなり停止されます。デーモンスレッドで使われたリソース (開いているファイル、データベースのトランザクションなど) は適切に解放されないかもしれません。きちんと (gracefully) スレッドを停止したい場合は、スレッドを非デーモンスレッドにして、Event のような適切なシグナル送信機構を使用してください。
前提として、Threadを殺すのは良くない →
強制終了は「リソースの解放が適切に行われないかもしれないので」良くない
質問の文章から、タイムアウトでスレッドの処理が中断されるのを
期待されてるよに見受けられますが、仮にそのような振る舞いをした場合は、
リソースの解放処理が適切に行われないので、
「良くない」とされるスレッドの終了方法に該当してしまいます。
例えば、スレッドで実行する処理を、
以下の様に置き換えて考えて見て下さい。
python
1 subjob("aaa") # リソース所得 ファイルopen等
2 subjob("bbb") # 時間の掛かる処理
3 subjob("ccc") # リソース解放 ファイルclose等
join(timeout=3) は、subjob("bbb") の途中で待機状態を解除するとします。
裏でタイムアウトしたスレッドが生きていて気持ち悪いです。
の「タイムアウトしたスレッド」が誤解だと思いますが、
(タイムアウトするのは、呼び出し側スレッドでの待機状態)
「~生きていて気持ち悪いです」ということは、
subjob("ccc") の部分は、実行してほしくないという事ですよね。
そうすると、subjob("bbb") で処理を中断することは、実際の処理に当てはめると
リソースの解放が行われないので、良くないスレッドの終了方法という事になります。
threadは殺すのは良くないということですが、解決方法を探しています。
おそらく、質問の意図は、
リソースの解放を考慮した「きちんとしたスレッドの停止」を行いたいのでしょうか。
回答としては、まずはスレッドで行う処理中に、
解放が必要なリソースがあるかどうか確認したうえで、
スレッド内で行う処理は、後処理が確実に実行されるように、
安全に中断可能な設計にする必要があります。
join(timeout) の後に、is_alive() を確認して、
生存(タイムアウト)だった場合は、
スレッドの処理を完了させるための通知を行います。
- 簡易的な方法であれば、フラグを設定してループを抜ける等
- signal で割り込み、例外を投げる (多分 windowsでは未対応)
但し、ライブラリ等の関数内で時間が掛かる処理がある場合は、
前者の方法では対応できません。
追記2:
質問のコードには書かれてませんが、
スクレイプという事なので、requests 等のライブラリをお使いでしょうか?
もし、ライブラリ側で対応しているなら、そちらの timeout オプションの利用が適してます。
thread.join(timeout=3) は、スケジュールのループを3秒間ブロックするので、
秒単位のスケジュールがある場合、3秒遅延になります。
ライブラリ側でのタイムアウトであれば、(質問のコードの構成の場合)別スレッドなので、
メインスレッドのスケジュールのループに影響ありません。
concurrency モジュールに言及しておくと、
concurrency.future には cancel() がありますが、
スケジュールされた実行前のタスクのキャンセルであって、
実行中の処理の中断とは異なります。
別の選択肢としては、非同期IOの導入
asyncio.Task の cancel() は、
実行中の処理の中断という用途には近いかもしれません。
asyncio対応ライブラリであれば、I/O処理待ちのタイミングでの中断が可能です。
追記
scheduleを使用するとデーモン化しても裏でまだスレッドが普通に生きてます。
ここも恐らく誤解だと思います、
どのようにスレッドの生存を確認したのでしょうか。
schedule の利用の有無に関わらず、デーモンスレッドが破棄されるのは、
「デーモンでない生存中のスレッドが全てなくなる」タイミングなので、
メインスレッドが終了した後です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。