Скрипт Python висит в цикле - PullRequest
1 голос
/ 30 марта 2011

В одном из моих сценариев я использую следующий бесконечный цикл для проверки активного интернет-соединения:

def online_check():
    try:
        con = urllib2.urlopen("http://www.google.com/")
        data = con.read()
        logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
    except:
        logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
        time.sleep(3)
        online_check()

Я знаю, что это не очень элегантное решение, но проблема в том, что когда я запускаю свой скрипт, он иногда вызывает метод online_check и застревает в середине его (один раз из примерно 200 попыток). Сценарий все еще выполняется, и исключение не выдается; скрипт просто застрял. Я могу нажать CTRL + C (даже после нескольких часов работы скрипта), и он просто выдаст исключение и продолжит следующую проверку online_check. Я также переписал скрипт для проверки IP-адреса в 'ifconfig', а не для проверки связи с Google, к сожалению, с похожими результатами.

Что я делаю не так? Могу ли я переписать сценарий, чтобы этого никогда не произошло? Что я могу сделать, чтобы узнать, что здесь происходит?

Помощь очень ценится. Btw. Я использую Python2.7.1 и пробовал этот скрипт как на Linux, так и на Mac.

P.S .: Если у вас есть рекомендации по разработке метода проверки подключения без использования полосы пропускания и минимальных накладных расходов, я был бы более чем рад это услышать.

Ответы [ 4 ]

4 голосов
/ 30 марта 2011

Вы столкнулись с бесконечной рекурсией, метод, который вы можете сделать, чтобы этого не произошло, - передать аргумент в online_check для максимальной проверки.

Например:

def online_check(max_checks=10, current_check=0):
    try:
        con = urllib2.urlopen("http://www.google.com/")
        data = con.read()
        logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
    except:
        logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
        if max_checks > current_check:
          time.sleep(3)
          online_check(max_checks, current_check+1)

Так вы бы сделали:

online_check(5) # for 5 maximum checks
online_check() # use the default value, which is 10

Я также предлагаю вам перехватить более конкретные исключения, чтобы улучшить привычки кодирования, а также потому, что когда вы выполняете CTRL-C, Python генерирует исключение KeyboardInterrupt, которое ваш код фактически перехватывает, потому что вы перехватываете все исключения.

3 голосов
/ 30 марта 2011

В дополнение к бесконечной рекурсии (насколько я знаю, CPython не поддерживает оптимизированную хвостовую рекурсию), вы не закрываете свое соединение.

Возможно, вы достигли какого-то ограничения на соединение либо с ОС, либо с Google при повторных попытках. Это, вероятно, происходит до достижения максимальной глубины рекурсии, поэтому вы не получите исключения.

Соединение обычно закрывается при сборке мусора, но я думаю, что из-за рекурсии переменная не полностью выходит из области видимости, пока рекурсия не завершится.

Также, как упоминал @senderle, вы должны попытаться отследить более конкретную ошибку.

Попробуйте:

def online_check():
  while True:
    try:
      con = urllib2.urlopen("http://www.google.com/")
      data = con.read()
      logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
    except urllib2.URLError:
      logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
      time.sleep(3)
    finally:
      con.close()

(Предупреждение непроверенного кода)

2 голосов
/ 30 марта 2011

В дополнение к предложениям других, вы должны указать, какие исключения вы ловите.Control-C не работает, потому что это просто вызывает исключение, и ваш оператор except интерпретирует его как то же самое, что и все другие.

Похоже, что вы хотите исключение urllib2.URLError.

1 голос
/ 30 марта 2011

В какой-то момент эта программа столкнется с пределом глубины рекурсии для вашего переводчика.Как правило, функция, которая должна работать постоянно, будет иметь такую ​​структуру:

def online_check():
  while True:
    try:
      con = urllib2.urlopen("http://www.google.com/")
      data = con.read()
      logging.debug('{0} Reached the host. Exiting online_check'.format(time.strftime('[ %H:%M:%S ]')))
      break
    except:
      logging.debug('{0} Could not reach host trying again in 3 seconds'.format(time.strftime('[ %H:%M:%S ]')))
      time.sleep(3)

Это должно дать вам лучшие результаты.Я полагаю, у вас уже есть отдельный поток, который выполняет эту функцию (в противном случае более поздний код не может быть выполнен - ​​эта функция никогда не вернется).

...