Я записал поисковый робот, который я хотел бы смочь остановить через клавиатуру. Я не хочу, чтобы программа умерла, когда я прерываю ее; это должно сбросить свои данные к диску сначала. Я также не хочу ловить 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
и процесс выходит полностью. Почему это происходит? Существует ли способ, которым я могу препятствовать тому, чтобы прерывание влияло на системный вызов?
socket.recv ()
вызывает базовую POSIX-совместимую функцию recv
на уровне C, которая, в свою очередь, возвращает код ошибки. EINTR
, когда процесс получает SIGINT
во время ожидания входящих данных в recv ()
. Этот код ошибки можно использовать на стороне C (если вы программировали на C), чтобы обнаружить, что recv ()
вернул не потому, что в сокете больше данных, а потому, что процесс получил SIGINT
. В любом случае, этот код ошибки превращается в исключение Python, и, поскольку он никогда не перехватывается, он завершает ваше приложение с отслеживанием, которое вы видите. Решение состоит в том, чтобы просто перехватить socket.error
, проверить код ошибки и, если он равен errno.EINTR
, игнорировать исключение без уведомления. Примерно так:
import errno
try:
# do something
result = conn.recv(bufsize)
except socket.error as (code, msg):
if code != errno.EINTR:
raise