2012-03-26 20 views
6

¡Esto es lo más extraño!El sistema operativo comienza a matar procesos cuando se ejecuta el proceso de python de subprocesos múltiples

Tengo una aplicación de cliente multiproceso escrita en Python. Estoy usando subprocesos para descargar y procesar páginas simultáneamente. Utilizaría el multi-identificador cURL, excepto que el cuello de botella es definitivamente el procesador (no el ancho de banda) en esta aplicación, por lo que es más eficiente usar un grupo de subprocesos.

Tengo un 64b i7 balanceo de 16 GB de RAM. Fornido. ¡Lanzo 80 hilos mientras escucho Pandora y trolleando Stackoverflow y BAM! El proceso padre a veces termina con el mensaje

Killed

Otras veces una página única (que es su propio proceso en Chrome) morirán. Otras veces, el navegador completo se bloquea.

Si quieres ver un poco de código aquí es el quid de la cuestión:

Aquí es el proceso padre:

def start(): 
    while True: 
    for url in to_download: 
     queue.put((url, uri_id)) 

    to_download = [ ] 

    if queue.qsize() < BATCH_SIZE: 
     to_download = get_more_urls(BATCH_SIZE) 

    if threading.activeCount() < NUM_THREADS: 
     for thread in threads: 
     if not thread.isAlive(): 
      print "Respawning..." 
      thread.join() 
      threads.remove(thread) 
      t = ClientThread(queue) 
      t.start() 
      threads.append(t) 

    time.sleep(0.5) 

Y aquí es la esencia de la ClientThread:

class ClientThread(threading.Thread): 

    def __init__(self, queue): 
    threading.Thread.__init__(self) 
    self.queue = queue 

    def run(self): 
    while True: 
     try: 
     self.url, self.url_id = self.queue.get() 
     except: 
     raise SystemExit 

     html = StringIO.StringIO() 
     curl = pycurl.Curl() 
     curl.setopt(pycurl.URL, self.url) 
     curl.setopt(pycurl.NOSIGNAL, True) 
     curl.setopt(pycurl.WRITEFUNCTION, html.write) 
     curl.close() 

     try: 
     curl.perform() 
     except pycurl.error, error: 
     errno, errstr = error 
     print errstr 

     curl.close() 

EDITAR: Ah, claro ... se olvidó de hacer la pregunta ... debería ser obvio: ¿Por qué mis procesos son asesinados? ¿Está sucediendo en el nivel del sistema operativo? Nivel de kernel? ¿Esto se debe a una limitación en la cantidad de conexiones TCP abiertas que puedo tener? ¿Es un límite en la cantidad de hilos que puedo ejecutar a la vez? La salida de cat /proc/sys/kernel/threads-max es 257841. Entonces ... No creo que sea eso ...

Creo que lo tengo ... OK ... No tengo espacio de intercambio en mi disco. ¿Hay alguna manera de crear un espacio de intercambio ahora? Estoy ejecutando Fedora 16. Hubo intercambio ... luego habilité toda mi memoria RAM y desapareció mágicamente. Tizón /var/log/messages me encontré con este error:.

Mar 26 19:54:03 gazelle kernel: [700140.851877] [15961] 500 15961 12455  7292 1  0    0 postgres 
Mar 26 19:54:03 gazelle kernel: [700140.851880] Out of memory: Kill process 15258 (chrome) score 5 or sacrifice child 
Mar 26 19:54:03 gazelle kernel: [700140.851883] Killed process 15258 (chrome) total-vm:214744kB, anon-rss:70660kB, file-rss:18956kB 
Mar 26 19:54:05 gazelle dbus: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper) 
+1

Compruebe la salida 'dmesg (8)' para ver si el núcleo registraba alguna información. – sarnold

+0

Gracias ... haré ... – KeatsKelleher

+0

las últimas entradas en 'dmesg (8)' pertenecen a mi adaptador wifi que se asocia con mi enrutador. ... que fue hace horas – KeatsKelleher

Respuesta

7

Usted ha desencadenado la del núcleo Controlador fuera de memoria (OOM); selecciona qué procesos matar de una manera complicada que intenta difícil de matar cuantos menos procesos como sea posible para lograr un mayor impacto. Chrome aparentemente hace el proceso más atractivo para matar según los criterios que usa el kernel.

se puede ver un resumen de los criterios en el proc(5) página de manual bajo el archivo /proc/[pid]/oom_score:

/proc/[pid]/oom_score (since Linux 2.6.11) 
      This file displays the current score that the kernel 
      gives to this process for the purpose of selecting a 
      process for the OOM-killer. A higher score means that 
      the process is more likely to be selected by the OOM- 
      killer. The basis for this score is the amount of 
      memory used by the process, with increases (+) or 
      decreases (-) for factors including: 

      * whether the process creates a lot of children using 
      fork(2) (+); 

      * whether the process has been running a long time, or 
      has used a lot of CPU time (-); 

      * whether the process has a low nice value (i.e., > 0) 
      (+); 

      * whether the process is privileged (-); and 

      * whether the process is making direct hardware access 
      (-). 

      The oom_score also reflects the bit-shift adjustment 
      specified by the oom_adj setting for the process. 

se puede ajustar el archivo oom_score para su programa de Python si se quiere que sea la que se mató.

Probablemente el mejor enfoque es agregar más swap a su sistema para tratar de impulsar el tiempo cuando se invoca el OOM-killer. Por supuesto, tener más intercambio no significa necesariamente que su sistema nunca se quedará sin memoria, y es posible que no se preocupe por la forma en que lo maneja si hay mucho tráfico de intercambio, pero al menos puede hacer que se escape. problemas de memoria

Si ya ha asignado todo el espacio disponible para las particiones de intercambio, puede agregar archivos de intercambio. Debido a que pasan por el sistema de archivos, hay más sobrecarga para los archivos de intercambio que las particiones de intercambio, pero puede agregarlos después de que la unidad esté particionada, lo que la convierte en una solución fácil a corto plazo. Utiliza el comando dd(1) para asignar el archivo (no utiliza seek para crear un archivo disperso) y luego usa mkswap(8) para formatear el archivo para su uso de intercambio, luego usa swapon(8) para activar ese archivo específico. (Creo que incluso puede agregar archivos de intercambio a fstab(5) para que estén disponibles automáticamente en el próximo reinicio, también, pero nunca he intentado y no conozco la sintaxis.)

+0

Gracias, hombre :) ¡Esto es todo! – KeatsKelleher

0

Usted está haciendo un

raise SystemExit 

que en realidad sale del intérprete de Python y no el hilo está ejecutando en

+0

Eso está bien, no explica por qué un proceso completamente separado muere. Ver editar arriba. – KeatsKelleher

Cuestiones relacionadas