• Publicidad

Creación procesos fork asíncronos

Así que programas sin strict y las expresiones regulares son otro modo de hablar. Aquí encontrarás respuestas de nivel avanzado, no recomendable para los débiles de corazón.

Creación procesos fork asíncronos

Notapor chrcperl » 2008-04-11 17:51 @785

Quiero crear procesos asíncronos con fork pero cuando lo hago siguen siendo síncronos. El código que uso es

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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
    }
}
 
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


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.
chrcperl
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2008-04-11 17:40 @778

Publicidad

Notapor Perl user » 2008-04-11 18:40 @819

¿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,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor chrcperl » 2008-04-12 10:27 @477

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:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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";
}
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


El código de la función
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
&simulate_gsrvu_execservice($process);
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


es:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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;
}
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4



y la salida de dicho programa es:

Código: Seleccionar todo
        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.
chrcperl
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2008-04-11 17:40 @778

Notapor explorer » 2008-04-12 10:47 @491

¿No estarás en Windows, verdad?
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor chrcperl » 2008-04-12 11:12 @508

No, estoy en Linux
chrcperl
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2008-04-11 17:40 @778

Notapor Perl user » 2008-04-12 12:56 @580

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:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
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;
}
 
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Saludos,
Marco A. Manzo
[email protected]
http://www.unixmonkeys.com/amnesiac/
Perl Programming Language
Perl user
Maestro honorario
Maestro honorario
 
Mensajes: 271
Registrado: 2004-11-03 21:11 @924

Notapor chrcperl » 2008-04-14 11:51 @535

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).
chrcperl
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2008-04-11 17:40 @778

Notapor chrcperl » 2008-04-14 12:14 @551

Probé el código anterior y observo que la ejecución del programa se queda en

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
while (my $line = <$child>) {
    print $line;
}

print "continua\n";
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


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).
chrcperl
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2008-04-11 17:40 @778


Volver a Avanzado

¿Quién está conectado?

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