2013-07-30 3 views
5

У меня есть приложение, которое каждые несколько минут проверяет группу серверов. Чтобы сделать это, он запускает один поток на сервер опрос (15 серверов) и записывает обратно данные к объекту:Причина выхода из строя Python

import requests 

class ServerResults(object): 
    def __init__(self): 
     self.results = [] 

    def add_server(some_argument): 
     self.results.append(some_argument) 

servers = ['1.1.1.1', '1.1.1.2'] 
results = ServerResults() 

for s in servers: 
    t = CallThreads(poll_server, s, results) 
    t.daemon = True 
    t.start() 

def poll_server(server, results): 
    response = requests.get(server, timeout=10) 
    results.add_server(response.status_code); 

CallThreads класса является вспомогательной функцией для вызова функции (в данном случае poll_server() с аргументами (в этом случае s и results), вы можете увидеть источник в моем реестре Github от Python utility functions. В большинстве случаев это работает нормально, однако иногда поток прерывисто висит. Я не уверен, почему, поскольку я использую timeout в запросе GET. В любом случае, если поток зависает, то зависающие потоки накапливаются в течение часов или дней, а затем сбой Python:

File "/usr/lib/python2.7/threading.py", line 495, in start 
    _start_new_thread(self.__bootstrap,()) 
thread.error: can't start new thread 

Exception in thread Thread-575 (most likely raised during interpreter shutdown) 
Exception in thread Thread-1671 (most likely raised during interpreter shutdown) 
Exception in thread Thread-831 (most likely raised during interpreter shutdown) 

Как я могу справиться с этим? Кажется, нет никакого пути к killablockingthreadinPython. Это приложение должно работать на малине Pi, поэтому большие библиотеки, такие как twisted, не подходят, на самом деле мне также нужно избавиться от библиотеки requests!

+0

Во-первых, это на пи, когда он висит, или вы проводите тестирование в другом месте? Могут быть инструменты для конкретной платформы, которые помогут увидеть, что делает поток, но вы не указали свою платформу. – Useless

+0

Во-вторых, что такое 'запросы'?Не видя этого, невозможно сказать, есть ли в нем состояние гонки – Useless

+0

В-третьих, даже если вы не используете скрученный, синхронный неблокирующий ввод-вывод в одном потоке гораздо более масштабируемый, чем этот – Useless

ответ

4

Насколько я могу судить, возможно сценарий заключается в том, что когда поток «зависает» для одного заданного сервера, он останется там «навсегда». В следующий раз, когда вы запрашиваете свои серверы, появляется другой поток (_start_new_thread), вплоть до того, что Python падает.

Вероятно, не ваша (основная) проблема, но вы должны:

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

Что касается «повесить» по себе - берегитесь, что таймаут аргумент в то время как «открытие URL» (urlopen) связан с тайм-аута для установления соединения. Не для загрузки фактических данных:

Необязательный параметр тайма-аута задает таймаут в секундах для блокирующих операций, как попытка подключения (если не указано, будет использоваться параметр таймаута глобального по умолчанию). Это фактически работает только для HTTP, HTTPS и FTP-соединений.

+0

Спасибо. На самом деле, я знаю, что тайм-аут предназначен только для соединения, 'запросы', похоже, не показывают способ отключения времени загрузки. Мне нравится идея одного потока на сервер, но когда поток зависает, тогда сервер, о котором идет речь, больше не будет опрошен. – dotancohen

+0

@dotancohen Ни urllib2, ни запросы не выставляют объект сокета, я думаю. Таким образом, вы, вероятно, должны [socket.setdefaulttimeout] (http://docs.python.org/2/library/socket.html#socket.setdefaulttimeout) исправить тайм-аут операции ввода-вывода * непосредственно перед открытием вашего подключения (и возможно, перезагрузив его позже). Что касается использования пула потоков, то мой * guess * был тогда, когда сервер блокировал входящий запрос из потока, он блокирует все последующие попытки подключения. но, возможно, потоки «случайно»? –

+0

Спасибо Сильвен, я посмотрю на тайм-аут сокета. Хорошая находка! Серверы разрешают последующие подключения, иначе следующие потоки не смогут опросить их. Я действительно не знаю, что вызывает зависание или даже где начать его отлаживать. – dotancohen

Смежные вопросы