Vie Abr 11, 2008 4:51 pm
|
 |
chrcperl
Perlero Nuevo

|
Registrado: 11 Abr 2008
Mensajes: 6
|
|
| Creación procesos fork asíncronos |
|
|
Quiero crear procesos asíncronos con fork pero cuando lo hago siguen siendo síncronos. El código que uso es
| Perl: | for $process (1.. 3) {
FORK: {
if (my $pid = fork()) {
# Padre
# No hace nada puesto que se relanza
# uno para cada proceso.
print "\n\tTamano de la pila:", scalar(@stack), "\n";
} elsif (defined $pid) {
# Hijo
$reschild= &simulate_gsrvu_execservice ($process);
$sreschild= &gserialize ( % {$reschild} );
push @stack, $sreschild;
exit;
} elsif ($! == EAGAIN ) {
print ("Error: EAGAIN\n");
sleep 1;
redo FORK;
} else {
print "Error al hacer fork(): $!\n";
} # fin FORK
}
}
|
Lo que quiero es ejecutar este proceso &simulate_gsrvu_execservice($process); asíncronamente pero veo que aún lo sigue haciendo de forma síncrona. Alguien tiene una idea. |
|
|
|

Vie Abr 11, 2008 5:40 pm
|
 |
Perl user
Maestro Honorario

|
Registrado: 03 Nov 2004
Mensajes: 385
|
|
|
|
|
¿Hablas en serio?
Jamás he visto un proceso síncrono desde hace muchos años, desde la invención de los planificadores que usan porciones de tiempo para cada ejecución de cada proceso. Dicho esto, dudo MUCHO que tus procesos sean "serializados", a menos que te valgas de algún tipo de mecanismo de comunicación entre procesos y los serialices tu mismo.
Por otro lado, lo que tienes en ese fork es un árbol de 8 procesos.
También como comentario.. no encuentro el motivo de checar por EAGAIN, no veo ninguna llamada a I/O no bloqueante o alguien que pueda arrojar ese error. Y por último... el estilo del código me recuerda a Perl 4
Mi recomendación es que... independientemente del lenguaje, verifiques cómo funciona un proceso en general, y después pases a la documentación del lenguaje para ver las funciones que éste proporciona. Fork en el caso de Perl (ya que depende de la llamada al sistema fork(1)), crea una nueva imagen del proceso que la generó, y a partir de allí cada uno tiene vida propia. Cada proceso tendrá un determinado tiempo de ejecución, este tiempo está dictado por el planificador del sistema operativo y NO HAY MANERA DE MODIFICARLO o de realmente saber el orden de ejecución.
Un saludo, |
|

Sab Abr 12, 2008 9:27 am
|
 |
chrcperl
Perlero Nuevo

|
Registrado: 11 Abr 2008
Mensajes: 6
|
|
|
|
|
De pronto no esté usando el termino "síncrono" correctamente, de pronto debí usar secuencial.
Lo que intento hacer es lanzar varios procesos (función &simulate_gsrvu_execservice($process); ) capturar la salida de este proceso y pasar dicha salida al proceso padre.
El código lo he modificado (teniendo en cuenta tus comentarios), es:
| Perl: |
my ($process, @stack, $msg, $pid);
#pila de procesos
foreach $process (1.. 3) {
pipe(FROM_CHILD, TO_PARENT ) or die "Error. pipe: $!";
select( (select(TO_PARENT ), $| = 1)[0] ); # autoflush
$pid = fork;
if ($pid) {
# Padre
close TO_PARENT;
chomp($line = <FROM_CHILD>);
push @stack, $line;
print "\t[PILA] ", $stack[ $ #stack ], "\n\n";
close FROM_CHILD;
} elsif (defined $pid) {
# Hijo
my ($reschild, $sreschild);
close FROM_CHILD;
$reschild= &simulate_gsrvu_execservice ($process);
$sreschild= &gserialize ( % {$reschild} );
print TO_PARENT $sreschild;
close TO_PARENT;
exit(0);
} else {
print "Error al hacer fork(): $!\n";
} # fin FORK
}
print "\n\nTamano de la pila:", scalar(@stack), "\n";
foreach $process (@stack) {
print "[PILA] $process\n";
}
|
El código de la función
| Perl: |
&simulate_gsrvu_execservice($process);
|
es:
| Perl: |
sub simulate_gsrvu_execservice {
my $param = $_[0];
my (%request, %tmp, $strhash, $tdelay);
#simula la demora del proceso
$tdelay = int(rand(10) + 1);
print "\tDemora proceso $param [$tdelay]\n";
#sleep $tdelay;
foreach(1.. 1 * $tdelay) { print "$param\n"; sleep 1 }
$tmp{param }= $param;
$tmp{delay }= $tdelay;
$strhash= &gserialize (%tmp);
$request{'data'}{'GWFLW'}= $strhash;
print "\tFIN proceso $param [$tdelay]\n";
return \ %request;
}
|
y la salida de dicho programa es:
| Código: |
Demora proceso 1 [3]
1
1
1
FIN proceso 1 [3]
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>4,'param'=>1)')})
Demora proceso 2 [2]
2
2
FIN proceso 2 [2]
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>8,'param'=>2)')})
Demora proceso 3 [3]
3
3
3
FIN proceso 3 [3]
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>3,'param'=>3)')})
Tamano de la pila:3
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>4,'param'=>1)')})
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>8,'param'=>2)')})
[PILA] __HASH__=('data'=>{('GWFLW'=>'__HASH__=('delay'=>3,'param'=>3)')}) |
Como pueden ver la ejecución de los procesos son secuenciales (hasta que no termina uno, no empieza el otro) y lo que quiero es que no sean secuenciales.
Espero haberme explicado mejor, para que me puedan ayudar. |
|

Sab Abr 12, 2008 9:47 am
|
 |
explorer
Moderador

|
Registrado: 24 Jul 2005
Mensajes: 4092
Ubicación: Valladolid, España
|
|
|
|
|
| ¿No estarás en Windows, verdad? |
|
Sab Abr 12, 2008 10:12 am
|
 |
chrcperl
Perlero Nuevo

|
Registrado: 11 Abr 2008
Mensajes: 6
|
|
|
|
|
| No, estoy en Linux |
|

Sab Abr 12, 2008 11:56 am
|
 |
Perl user
Maestro Honorario

|
Registrado: 03 Nov 2004
Mensajes: 385
|
|
|
|
|
El problema es el siguiente...
En el momento que creas el primer proceso sucede:
1) El proceso padre invoca al operador <> para realizar E/S sobre dicho filehandle, el cual, a menos que tenga algo qué leer, se pondrá a esperar.
2) El proceso hijo se pone a ejecutar la subrutina que indicas, la cual contiene un ciclo que imprime ciertos valores. Como hasta ese punto sólo esos dos procesos son los únicos que existen, siempre serán los únicos que se van a comunicar. No existe ninguna manera de ceder el paso al siguiente proceso, con dicha estructura.
Y el problema es que tu esperas que los demás procesos se ejecuten asíncronamente; lo que no estás cuidando es que TU mismo los estás serializando ya que hasta que no termine el primer fork, el segundo comienza.
Hay varias soluciones a este problema, y la mas obvia es PRE-FORKING, qué es una técnica muy utilizada por algunos servidores WEB la cual consiste en levantar una cantidad inicial de procesos que estén listos para atender N cantidad de operaciones. Con esto garantizas que... como los procesos hijo fueron creados inicialmente, cada uno podrá procesar de manera independiente las peticiones que lleguen.
Y para poder comunicar a los procesos hijo con el proceso principal existen varios mecanismos. El uso de un simple pipe no es muy seguro, ya que varios hijos intentarán escribir sobre el mismo canal al mismo tiempo. Soluciones para eso puede ser el uso de un UNIX Socket o un fifo. Otras soluciones pueden ser el uso de AIO (Asynchronous I/O) e incluso otras soluciones pueden ser el involucrar el uso de select() para multiplexar E/S entre cada hijo cuando este tenga información para el padre.
La recomendación es que... como ignoro el problema que intentas solucionar, sería interesante ver qué es lo que realmente quieres resolver y buscar posiblemente una solución idónea...
De todos modos pongo una pequeña solución levantando primeramente 3 procesos y hasta después el padre toma la salida de cada uno. Cabe señalar que no agregué ningún tipo de limpieza para los procesos hijos ni nada, con el fin de ejemplificar:
| Perl: |
use strict;
use warnings;
use IO:: Handle;
my ($child, $parent);
pipe $child, $parent or die $!;
$child-> autoflush(1);
$parent-> autoflush(1);
for my $p (1.. 3) {
defined(my $pid = fork) or die $!;
if ($pid) {
for (1.. 10) {
sleep 1 * int(rand 3);
print $parent "$p: $_\n";
}
exit;
}
}
while (my $line = < $child> ) {
print $line;
}
|
Saludos, |
|

Lun Abr 14, 2008 10:51 am
|
 |
chrcperl
Perlero Nuevo

|
Registrado: 11 Abr 2008
Mensajes: 6
|
|
|
|
|
Excelente tu respuesta, muchas gracias, voy a probar y luego les cuento.
Mientras, les agradeceria que me aconsejaran donde puedo encontrar información sobre PRE-FORKING, sobre como hacer fifo y sobre el uso de AIO (Asynchronous I/O). |
|
Lun Abr 14, 2008 11:14 am
|
 |
chrcperl
Perlero Nuevo

|
Registrado: 11 Abr 2008
Mensajes: 6
|
|
|
|
|
Probé el código anterior y observo que la ejecución del programa se queda en
| Perl: | while (my $line = < $child> ) {
print $line;
}
print "continua\n"; |
Creo que debo usar alguno de los otros métodos que me indica y no usar los pipe.
Les agradecería que me aconsejaran dónde puedo encontrar información sobre PRE-FORKING, sobre cómo hacer fifo y sobre el uso de AIO (Asynchronous I/O). |
|
Powered by phpBB © 2001, 2005 phpBB Group
|