• Publicidad

Parallel ForkManager error

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Parallel ForkManager error

Notapor colorado » 2011-02-12 16:41 @737

Tengo el siguiente script:

Sintáxis: [ Descargar ] [ Ocultar ]
  1. open (URLS, 'urls3.txt'); 
  2. my @urls = <URLS>; 
  3. chomp @urls; 
  4. close(URLS); 
  5. open (PROXY, 'proxy.txt'); 
  6. my @proxy = <PROXY>; 
  7. chomp @proxy; 
  8. close(PROXY); 
  9.  
  10. my $l = @urls; 
  11.  
  12. my $forker     = Parallel::ForkManager->new(20); 
  13.  
  14. for (my $i = 0; $i < @proxy; $i++) { 
  15.  
  16. $forker->start and next; 
  17.  
  18.  
  19. print $urls[$i % $l]," 
  20. "," PROXY: ",$proxy[$i]," 
  21.  
  22. "; 
  23.  
  24. $ua = new LWP::UserAgent(); 
  25. $ua->agent("Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)"); 
  26. $resp = $ua->request(GET "$urls[$i % $l]"); 
  27.      
  28.  
  29.  
  30.  
  31. open(ARCHIVO,">>libros.txt"); 
  32. binmode ARCHIVO; 
  33. print ARCHIVO $resp->{_content}," 
  34. ",$proxy[$i]; 
  35. close(ARCHIVO); 
  36.  
  37. $forker->finish; 
  38.  
  39. }; 


Lo estoy ejecutando con una conexión directa, como se ve en el script, no incluyo la ejecución de proxies.

En mi lista de proxies, tengo una larguísima recopilación de ellos.

El script funciona como quiero, pero después de un rato marca el siguiente error:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Cannot fork: Resource temporarily unavailable at C:/Perl/site/lib/Parallel/ForkManager.pm line 472.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


He intentado esquivar el error de varias formas:

* bajando la velocidad la velocidad ForkManager->new(5)
(al bajar la velocidad consigo más respuestas pero al final termina por salir el mismo mensaje)

* incluyendo sleep() en el script para relajar la descarga (con esto no consigo nada)

* probando con versiones anteriores del archivo ForkManager.pm

... pero no consigo pasar toda la lista de proxies.

¿¿Alguien me puede ayudar a esquivar este error si es que se puede??


Un saludo
colorado
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2010-01-31 14:48 @658

Publicidad

Re: Parallel ForkManager error

Notapor explorer » 2011-02-12 19:50 @868

El aviso que sale no es un error del programa, sino un aviso del sistema operativo. Indica que no es capaz de generar un fork() más.

Lo primero que tienes que ver es saber qué limite tiene tu sistema operativo para realizar los fork().

Por ejemplo, en mi casa sale:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
explorer@casa:~> ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 19828
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) 2166732
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 19828
virtual memory          (kbytes, -v) 2881040
file locks                      (-x) unlimited
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Y ahí indica que puedo generar un máximo de 19828 procesos (en ese momento), pero no puedo mantener abiertos más de 1024 ficheros de forma simultánea.

Estos límites suelen estar definidos en un fichero como este: /etc/security/limits.conf

El parámetro que pasas al método new() de P::M no es la velocidad, sino el número máximo de procesos simultáneos que se deben generar. En caso de que el usuario (el bucle for()) necesite más, hará un wait() para esperar que algún hijo termine, antes de generar el siguiente. Si pones 30, pues ese será el número máximo de procesos.

Hay un problema muy claro, y es que todos los hijos están compitiendo por añadir información al fichero libros.txt. Los resultados pueden ser desastrosos si dos o más hijos acceden al fichero a la vez.

Es mejor usar el método finish(), usando su segundo parámetro, en el que el hijo podrá pasar información al padre (hay una sección del manual de P::M que lo explica.

Es extraño el mensaje de error. Lo normal es que no se generen tantos procesos, sino los marcados en el máximo. Podría ser... que algunas peticiones se alargasen mucho y los hijos no terminen nunca, por lo que los procesos quedan siempre esperando.

Una forma de solventarlo podría ser capturar el error, con un eval(). Tienes que meter el start() dentro del eval(). Si el start() funciona, ejecuta el next(). Sino, a la salida del eval() debes comprobar el valor de @!. Si contiene algo, es que ha ocurrido un error. En ese caso, yo avisaría en pantalla, pondría un sleep() generoso, y volvería a intentarlo de nuevo (redo). Si no hay @!, entonces sigo con la captura de la página.

No sé si funcionará eso, pero la captura de errores del die() (que es la causa del mensaje de error en la línea 472), se hace con eval(). De esa manera, el programa no termina de forma brusca y podemos tomar alguna medida.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parallel ForkManager error

Notapor colorado » 2011-02-13 06:47 @324

Gracias por la respuesta explorer.

He modificado el código, para que muestre errores en la ejecución del script.

Sintáxis: [ Descargar ] [ Ocultar ]
  1. open (URLS, 'urls3.txt'); 
  2. my @urls = <URLS>; 
  3. chomp @urls; 
  4. close(URLS); 
  5. open (PROXY, 'proxy.txt'); 
  6. my @proxy = <PROXY>; 
  7. chomp @proxy; 
  8. close(PROXY); 
  9.  
  10. my $l = @urls; 
  11.  
  12. my $forker     = Parallel::ForkManager->new(5); 
  13. eval { 
  14. for (my $i = 0; $i < @proxy; $i++) { 
  15.  
  16. $forker->start and next; 
  17.  
  18.  
  19. print $urls[$i % $l]," 
  20. "," PROXY: ",$proxy[$i]," 
  21.  
  22. "; 
  23.  
  24. $ua = new LWP::UserAgent(); 
  25. $ua->agent("Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)"); 
  26. $resp = $ua->request(GET "$urls[$i % $l]"); 
  27.      
  28.  
  29. open(ARCHIVO,">>libros.txt"); 
  30. binmode ARCHIVO; 
  31. print ARCHIVO $resp->{_content}," 
  32. ",$proxy[$i]; 
  33. close(ARCHIVO); 
  34.  
  35. sleep(20); 
  36.  
  37. die "child($i) die.\n"; 
  38.  
  39. $forker->finish; 
  40. print "esto no deberia imprimirse nunca"; 
  41.  
  42. $forker->wait_all_children; 
  43. print "ojala llegara aqui.\n"; 
  44. }; 
  45.  
  46. if ($@) { 
  47.   print "bien\n"; 
  48. else 
  49.     {    print "\t[ ERROR ]"; 
  50. sleep(5000); 
  51.     } 


Pero no muestra nada raro. Todo se ejecuta con normalidad.

Es extraño el mensaje de error. Lo normal es que no se generen tantos procesos, sino los marcados en el máximo. Podría ser... que algunas peticiones se alargasen mucho y los hijos no terminen nunca, por lo que los procesos quedan siempre esperando.


Va descargando las páginas de 5 en 5, hasta que no obtiene todas las respuestas, no pasa al siguiente bloque de 5.

No me llega a mostrar el mensaje de ERROR ni hace el sleep(). El programa se para siempre en la misma zona.


Hay un problema muy claro, y es que todos los hijos están compitiendo por añadir información al fichero libros.txt. Los resultados pueden ser desastrosos si dos o más hijos acceden al fichero a la vez.


He quitado el bloque en el que guarda la información de la respuesta, pero se para igualmente.


Estos límites suelen estar definidos en un fichero como este: /etc/security/limits.conf


Trabajo bajo Windows. ¿Cuál es el archivo en Windows donde están definidos esos límites? ¿Se podría modificar para alargar el proceso?
colorado
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2010-01-31 14:48 @658

Re: Parallel ForkManager error

Notapor explorer » 2011-02-13 08:10 @382

El fork() de Perl en Windows tiene unas particularidades... la principal es que NO crea procesos independientes, de la misma forma que en los UNIX/Linux.

Una opción es usar el Perl de ActiveState, que ha creado una versión de fork() especial para emular el mismo comportamiento. A diferencia de UNIX/Linux, en que los procesos hijos son auténticos procesos independientes del padre, en Windows son hilos de ejecución dependientes del padre (la página anterior los llama pseudo-procesos).

En otra página te dicen cómo calcular el límite de hilos que se pueden crear en Windows, que depende de si tu sistema es de 32 o 64 bits, el tamaño de la pila de procesos... lo normal es que sean decenas de miles. Mucho antes estará el límite de ficheros abiertos, sin duda.

Yo cambiaría de sistema operativo :)

Si no quieres contarnos qué quieres hacer, en detalle, puedes enviarme un mensaje privado para contármelo, y así intentar buscar otras soluciones alternativas.

Si el programa se para en el mismo sitio, debería ser fácil calcular el número de procesos que se han ejecutado hasta ese momento.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parallel ForkManager error

Notapor colorado » 2011-02-13 18:22 @807

He leído la información de la página que me pasaste, y lo que he entendido, es que el Parallel::ForkManager no mata los pseudo-procesos, los sigue ejecutando a lo largo de todo el script, hasta el limite que tiene marcado el sistema operativo.

La solución sería matar esos pseudo-procesos una vez obtenida la respuesta.

En conclusión Parallel::ForkManager, no me vale para lo que quiero hacer.

Me estudiaré lo de usar el Perl de ActiveState, a ver si puedo sacar algo.

En cuanto pueda te mando un privado explicando lo que quiero hacer.

Un saludo y gracias por toda tu ayuda.
colorado
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2010-01-31 14:48 @658

Re: Parallel ForkManager error

Notapor explorer » 2011-02-13 18:42 @820

Yo no he entendido eso... en el texto habla de que los hijos (los pseudo-procesos) deben morir antes de que el proceso padre pueda morir, pero es algo que debe ocurrir cuando se llega al finish(). De todas maneras, con un exit() debería ser suficiente. No sé, quizás en Windows sea distinto.

Yo recuerdo cuando lo probé hace 6 años, el fork() del Perl de ActiveState no creaba procesos, pero parece que ahora sí.

Lo dicho, yo cambiaría de sistema operativo. Puedes instalarte un Virtual Box, y dentro un Linux, y así lo tienes resuelto, sin tener que quitar el Windows.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Parallel ForkManager error

Notapor colorado » 2011-02-13 19:53 @870

Bueno sí, eso es lo que hace: coge el grupo de 5 hijos y cuando obtiene la respuesta, pasa al siguiente grupo de 5, pero lo que creo es que no los mata, los pseudo-procesos siguen manteniéndose activos.

En el administrador de tareas de Windows, la carga de transacciones va en aumento todo el tiempo, hasta que llega a 2600M y el programa rompe.

Pero no encuentro la manera de rebajar esa carga de transacciones. En fin, habrá que probar otras cosas.
colorado
Perlero nuevo
Perlero nuevo
 
Mensajes: 73
Registrado: 2010-01-31 14:48 @658


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 19 invitados