8

キーボードで停止できるようにしたいWebクローラーを作成しました。プログラムを中断したときにプログラムが停止することは望ましくありません。最初にデータをディスクにフラッシュする必要があります。KeyboardInterruptedExceptionまた、永続データが一貫性のない状態になる可能性があるため、キャッチしたくありません。

SIGINT私の現在の解決策は、フラグをキャッチして設定するシグナルハンドラーを定義することです。メインループの各反復は、次のURLを処理する前にこのフラグをチェックします。

ただし、socket.recv()割り込みを送信したときにシステムが実行されている場合は、次のようになります。

^C
Interrupted; stopping...  // indicates my interrupt handler ran
Traceback (most recent call last):
  File "crawler_test.py", line 154, in <module>
    main()
  ...
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py", line 397, in readline
    data = recv(1)
socket.error: [Errno 4] Interrupted system call

プロセスは完全に終了します。なぜこれが起こるのですか?割り込みがシステムコールに影響を与えるのを防ぐ方法はありますか?

4

2 に答える 2

9

socket.recv()C層で基盤となるPOSIX準拠の関数を呼び出します。この関数は、で着信データを待機している間にプロセスがしばらく受信するとrecv、エラーコードを返します。このエラーコードをC側で使用して(Cでプログラミングしている場合)、ソケットで使用可能なデータが多いためではなく、プロセスがを受信したために返されたエラーを検出できます。とにかく、このエラーコードはPythonによって例外に変換され、キャッチされることはないため、表示されるトレースバックでアプリケーションを終了します。解決策は、単にキャッチし、エラーコードをチェックし、それがに等しい場合は、例外を黙って無視することです。このようなもの:EINTRSIGINTrecv()recv()SIGINTsocket.errorerrno.EINTR

import errno

try:
    # do something
    result = conn.recv(bufsize)
except socket.error as (code, msg):
    if code != errno.EINTR:
        raise
于 2010-06-10T17:28:43.983 に答える
3

ソケット呼び出しを中断したくない場合は、シグナルハンドラーを設定した後、割り込み動作を無効にします。

signal.signal(<your signal here>, <your signal handler function here>)
signal.siginterrupt(<your signal here>, False)

シグナル処理関数で、threading.Event()などのフラグを設定してから、メインの処理関数でそのフラグを確認し、クローラーを正常に終了します。

ここの背景情報:

于 2015-06-18T15:49:01.757 に答える