error: no se puede iniciar un nuevo hilo

Tengo un sitio que se ejecuta con la siguiente configuración:

Django + mod-wsgi + apache

En una solicitud del usuario, envío otra solicitud HTTP a otro servicio y resuelvo esto mediante la biblioteca httplib de python.

Pero a veces este servicio no recibe respuesta por mucho tiempo, y el tiempo de espera para httplib no funciona. Así que estoy creando un hilo, en este hilo envío una solicitud al servicio y me uno a ella después de 20 segundos (20 segundos es un tiempo de espera de solicitud). Así es como funciona:

class HttpGetTimeOut(threading.Thread): def __init__(self,**kwargs): self.config = kwargs self.resp_data = None self.exception = None super(HttpGetTimeOut,self).__init__() def run(self): h = httplib.HTTPSConnection(self.config['server']) h.connect() sended_data = self.config['sended_data'] h.putrequest("POST", self.config['path']) h.putheader("Content-Length", str(len(sended_data))) h.putheader("Content-Type", 'text/xml; charset="utf-8"') if 'base_auth' in self.config: base64string = base64.encodestring('%s:%s' % self.config['base_auth'])[:-1] h.putheader("Authorization", "Basic %s" % base64string) h.endheaders() try: h.send(sended_data) self.resp_data = h.getresponse() except httplib.HTTPException,e: self.exception = e except Exception,e: self.exception = e 

algo como esto…

Y utilízalo por esta función:

 getting = HttpGetTimeOut(**req_config) getting.start() getting.join(COOPERATION_TIMEOUT) if getting.isAlive(): #maybe need some block getting._Thread__stop() raise ValueError('Timeout') else: if getting.resp_data: r = getting.resp_data else: if getting.exception: raise ValueError('REquest Exception') else: raise ValueError('Undefined exception') 

Y todo funciona bien, pero en algún momento empiezo a atrapar esta excepción:

 error: can't start new thread 

En la línea de inicio de nuevo hilo:

 getting.start() 

y la siguiente y última línea de trazabilidad es

 File "/usr/lib/python2.5/threading.py", line 440, in start _start_new_thread(self.__bootstrap, ()) 

Y la respuesta es: ¿Qué pasa?

Gracias por todo, y lo siento por mi inglés puro. 🙂

El error “no se puede iniciar un nuevo hilo” es casi seguro debido al hecho de que ya tiene demasiados hilos ejecutándose dentro de su proceso de Python, y debido a un límite de recursos de algún tipo, se rechaza la solicitud para crear un nuevo hilo.

Probablemente deberías mirar la cantidad de hilos que estás creando; El número máximo que podrá crear lo determinará su entorno, pero al menos debería estar en el orden de cientos.

Probablemente sería una buena idea repensar tu architecture aquí; Ya que esto se está ejecutando de forma asíncrona, tal vez podría usar un grupo de subprocesos para obtener recursos de otro sitio en lugar de siempre iniciar un subproceso para cada solicitud.

Otra mejora a considerar es su uso de Thread.join y Thread.stop; esto probablemente se lograría mejor al proporcionar un valor de tiempo de espera al constructor de HTTPSConnection.

Usted está iniciando más subprocesos de los que puede manejar su sistema. Hay un límite en el número de subprocesos que pueden estar activos para un proceso.

Su aplicación está iniciando subprocesos más rápido de lo que los subprocesos se están ejecutando hasta su finalización. Si necesita iniciar muchos subprocesos, debe hacerlo de una manera más controlada, sugeriría usar un grupo de subprocesos.

Creo que la mejor manera en su caso es establecer un tiempo de espera de socket en lugar de un hilo de generación:

 h = httplib.HTTPSConnection(self.config['server'], timeout=self.config['timeout']) 

También puede configurar el tiempo de espera predeterminado global con la función socket.setdefaulttimeout() .

Actualización : vea las respuestas a ¿Hay alguna forma de matar un hilo en Python? Pregunta (hay varias bastante informativas) para entender por qué. Thread.__stop() no finaliza el subproceso, sino que establece un indicador interno para que se considere ya detenido.

Reescribí completamente el código de httplib a pycurl.

 c = pycurl.Curl() c.setopt(pycurl.FOLLOWLOCATION, 1) c.setopt(pycurl.MAXREDIRS, 5) c.setopt(pycurl.CONNECTTIMEOUT, CONNECTION_TIMEOUT) c.setopt(pycurl.TIMEOUT, COOPERATION_TIMEOUT) c.setopt(pycurl.NOSIGNAL, 1) c.setopt(pycurl.POST, 1) c.setopt(pycurl.SSL_VERIFYHOST, 0) c.setopt(pycurl.SSL_VERIFYPEER, 0) c.setopt(pycurl.URL, "https://"+server+path) c.setopt(pycurl.POSTFIELDS,sended_data) b = StringIO.StringIO() c.setopt(pycurl.WRITEFUNCTION, b.write) c.perform() 

algo como eso.

Y lo estoy probando ahora. Gracias a todos por su ayuda.

Si está intentando establecer un tiempo de espera, ¿por qué no usa urllib2 ?

En mi caso, agregué este código antes de comenzar un nuevo hilo. Le da a la aplicación un límite máximo de subprocesos en ejecución esperará

 while threading.active_count()>150 : time.sleep(5) getting.start() 

Si está utilizando un ThreadPoolExecutor, el problema puede ser que su max_workers sea más alto que los subprocesos permitidos por su sistema operativo.

Parece que el ejecutor mantiene la información de los últimos subprocesos ejecutados en la tabla de procesos, incluso si los subprocesos ya están hechos. Esto significa que cuando su aplicación ha estado ejecutándose durante mucho tiempo, eventualmente se registrará en la tabla de procesos tantos hilos como ThreadPoolExecutor.max_workers