無限ループで実行され、データベースに何かを追加し、途中で停止できないことを行うスクリプトがあるので、Ctrl + Cを押して停止することはできません。
どういうわけか、whileループを停止できるようにしたいのですが、停止する前に最後の反復を終了させます。
明確にさせてください:
私のコードは次のようになります:
while True:
does something
does more things
does more things
私は、whileループを最後または最初で中断できるようにしたいのですが、それが悪いため、物事の間に中断することはできません。
そして、私が継続したいかどうか、毎回の繰り返しの後に尋ねられたくありません。
素晴らしい答えをありがとう、私はとても感謝していますが、私の実装は機能していないようです:
def signal_handler(signal, frame):
global interrupted
interrupted = True
class Crawler():
def __init__(self):
# not relevent
def crawl(self):
interrupted = False
signal.signal(signal.SIGINT, signal_handler)
while True:
doing things
more things
if interrupted:
print("Exiting..")
break
ctr + cを押すと、プログラムは私を無視し続けます
あなたがする必要があるのは、割り込みをキャッチし、割り込みを受けたことを示すフラグを設定しますが、(各ループの終わりに)フラグをチェックする時まで作業を続けます。 Pythonのtry-exceptコンストラクトはループの現在の実行を破棄するため、適切なシグナルハンドラーを設定する必要があります。割り込みは処理しますが、python中断したところから続行します。方法は次のとおりです。
_import signal
import time # For the demo only
def signal_handler(signal, frame):
global interrupted
interrupted = True
signal.signal(signal.SIGINT, signal_handler)
interrupted = False
while True:
print("Working hard...")
time.sleep(3)
print("All done!")
if interrupted:
print("Gotta go")
break
_
ノート:
コマンドラインから使用してください。 IDLEコンソールでは、IDLE自身の割り込み処理を踏みにじります。
より良い解決策は、ループの期間中はKeyboardInterruptを「ブロック」し、割り込みをポーリングするときはブロックを解除することです。これは一部のUnixフレーバーの機能ですが、すべてではないため、python サポートしていません (3番目の「一般規則」を参照)
OPはこれをクラス内で実行したいと考えています。しかし、割り込み関数は、信号処理システムによって2つの引数を指定して呼び出されます。信号番号とスタックフレームへのポインタです。クラスオブジェクトへのアクセスを提供するself
引数の場所はありません。したがって、フラグを設定する最も簡単な方法は、グローバル変数を使用することです。クロージャーを使用してローカルコンテキストへのポインターをリギングできます(つまり、__init__()
でシグナルハンドラーを動的に定義しますが、率直に言って、マルチスレッドまたはなんでも。
警告:プロセスがシステムコールの途中にある場合、シグナルを処理するとシステムコールが中断される場合があります。したがって、これはすべてのアプリケーションに対して安全であるとは限りません。より安全な代替策は、(a)信号に依存する代わりに、各ループ反復の終わりにノンブロッキング読み取りを使用します(^ Cを押す代わりに入力を入力します)。 (b)スレッドまたはプロセス間通信を使用して、ワーカーを信号処理から分離します。または(c)実装しているOSを使用している場合は、実際の シグナルブロッキング を実装します。それらはすべてある程度OSに依存しているので、それはそのままにしておきます。
以下のロジックはこれを行うのに役立ちます、
import signal
import sys
import time
run = True
def signal_handler(signal, frame):
global run
print "exiting"
run = False
signal.signal(signal.SIGINT, signal_handler)
while run:
print "hi"
time.sleep(1)
# do anything
print "bye"
これを実行中に、CTRL + Cを押してみてください
@ praba230890の解決策を明確にするには:interrupted
変数が正しいスコープで定義されていません。これはcrawl
関数で定義されており、ハンドラーはプログラムのルートでのハンドラーの定義に従って、グローバル変数として到達できませんでした。
以下のコードがあなたに役立つことを願っています:
#!/bin/python
import sys
import time
import signal
def cb_sigint_handler(signum, stack):
global is_interrupted
print "SIGINT received"
is_interrupted = True
if __name__ == "__main__":
is_interrupted = False
signal.signal(signal.SIGINT, cb_sigint_handler)
while(1):
# do stuff here
print "processing..."
time.sleep(3)
if is_interrupted:
print "Exiting.."
# do clean up
sys.exit(0)