2016-01-27 4 views
2

Я использую Plex и пытаюсь использовать Plex api для получения и постоянного обновления статуса моего Plex-сервера. Если статус меняется, у меня есть несколько вещей, которые он делает. Вот мой код (я отредактированный нерелевантные части):Python HTTP-запрос, который выполняется каждую секунду, бесконечно и сравнивается с предыдущей итерацией

import requests 
import time 

ip = '127.0.0.1' 
port = '####' 


def get_status(last_media_type, last_state): 
    data = requests.get('http://' + ip + ':' + port + '/status/sessions', verify=False) 
    if home: # Ignore this part. Redacted code 
     if '<MediaContainer size="0">' in data.text: # If nothing is playing 
      media_type = 'None' 
      state = 'STOPPED' 
     else: # Get what's playing and its status 
      media_type_start = data.text.find('type=\"') 
      media_type_end = data.text.find('updatedAt=') 
      media_type = data.text[media_type_start + 6:media_type_end - 2].capitalize() 
      print('Type: ' + str(media_type)) 
      state_prefix_start = data.text.find('<Player address=') 
      state_prefix_end = data.text.find('<TranscodeSession key=') 
      state_prefix = data.text[state_prefix_start:state_prefix_end] 
      state_start = state_prefix.find('state=\"') 
      state_end = state_prefix.find('title=') 
      state = state_prefix[state_start + 7:state_end - 2].upper() 
     if last_media_type != media_type or last_state != state: # THIS IS IMPORTANT. I don't want to execute the next part if nothing has changed. 
      # DO STUFF, redacted 
     if state == 'PLAYING': 
      interval = 1 
     elif state == 'PAUSED': 
      interval = 10 
     elif state == 'STOPPED': 
      interval = 15 
    else: 
     interval = 60 * 3 # if nobody home, only check once every 3 minutes 
    time.sleep(interval) 
    get_status(media_type, state) 

get_status('a', 'b') # filler arguments used to initiate script 

Проблема

К сожалению, через полчаса или около того, я получаю:

RecursionError: maximum recursion depth exceeded in comparison

Этот является трассировкой (хотя номера строк не совпадают из-за обработки):

Traceback (most recent call last): 
    File "H:/Users/micha/Documents/Scripts/Python/plexStatus.pyw", line 63, in <module> 
    p = psutil.Process(os.getpid()) # Get PID for this script 
    File "C:\Python351\lib\site-packages\psutil\__init__.py", line 349, in __init__ 
    self._init(pid) 
    File "C:\Python351\lib\site-packages\psutil\__init__.py", line 375, in _init 
    self.create_time() 
    File "C:\Python351\lib\site-packages\psutil\__init__.py", line 636, in create_time 
    self._create_time = self._proc.create_time() 
    File "C:\Python351\lib\site-packages\psutil\_pswindows.py", line 282, in wrapper 
    return fun(self, *args, **kwargs) 
    File "C:\Python351\lib\site-packages\psutil\_pswindows.py", line 422, in create_time 
    if self.pid in (0, 4): 
RecursionError: maximum recursion depth exceeded in comparison 

Вопросы,

Как я могу получить эту работу без ошибок рекурсии, пока еще только ждет 1 секунду между казнями?

Я предполагаю, что есть лучший способ вызвать этот скрипт, сохраняя возможность использовать переменные из предыдущего вызова. Я просто не могу понять, как это сделать. Я думаю, что могу использовать pickle, который я уже использую в другой отредактированной части, но я бы хотел избежать тонкости чтения/записи, если это возможно. Или, на самом деле, просто сделайте это как можно более маленьким, насколько это возможно, при сохранении функциональности.

Примечания: Я уверен, что есть лучший способ разбора. Я новичок в программировании. Исследуя это, я исправляю это.

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

Я знаю, что для этого есть инструменты, такие как PlexPy. Просто пытаюсь написать один, который меньше, и я могу работать постоянно, не будучи крупным ресурсом.

ответ

2

Рекурсия означает, что каждый вызов функции остается в стеке, поэтому в конечном итоге у вас закончится память, ведущая к RecursionError. В другом Есть способы обойти это с помощью «рекурсии хвоста», почти как вы сделали - except Python will never support this.

Лучший способ запустить это изменить код, чтобы иметь бесконечный цикл:

def get_status(last_media_type, last_state): 
    pass # your method here 
     # except for the recursive call 
    return state, media_type 

last_state = None 
last_media_type = 'sensible_default' 
while True: 
    state, media_type = get_status(last_media_type, last_state) 
    pass # do what you need to compare them here 

    if last_state != state and last_media_type != media_type: 
     print "they aren't equal!"  

    last_state, last_media_type = state, media_type 

Сама петля (while True:) не будет потреблять практически никакой памяти, и теперь вместо того, чтобы хранить каждое прошлое состояние, у вас есть только последний.

Кроме того, любая информация, содержащаяся в вызове метода собирают мусор, как он теряет объем, когда ваш метод возвращает - это прямое улучшение по сравнению с вашим кодом, как в рекурсивном вызове ничего никогда не теряет масштабы поэтому ничего не кал никогда не будет собрано ,

+1

Это сделало трюк. Благодаря!Я видел похожие ответы на это для других сценариев с той же проблемой, но не мог заставить их адаптироваться к работе с моими (все еще слишком новыми). Но это сделал трюк. Потребляемая память больше не поднимается на ~ 50K за рекурсию, и я не получаю ошибку. Спасибо за помощь! Sidenote: Есть ли лучший способ проанализировать ответ (он возвращается как xml). Я провел немало исследований, и мой путь казался лучшим/единственным. – syndac

+1

Невозможно отредактировать этот комментарий. Но я нашел более чистый способ анализа с помощью ElemenTree. – syndac

1

Вместо использования рекурсии вы можете использовать цикл while для бесконечного цикла. Рекурсия не бесконечна, поскольку, как вы видели, рекурсия увеличивает стек и, следовательно, ограничена.