Esta integral puede aproximarse por la suma:
lhp@nereida:~/Lperl/src/perl_networking/ch2$ cat -n pi.c
  1  #include <stdio.h>
  2  #include <stdlib.h>
  3
  4  main(int argc, char **argv) {
  5    int id, N, np, i;
  6    double sum, left;
  7
  8    if (argc != 4) {
  9      printf("Uso:\n%s id N np\n",argv[0]);
 10      exit(1);
 11    }
 12    id = atoi(argv[1]);
 13    N = atoi(argv[2]);
 14    np = atoi(argv[3]);
 15    for(i=id, sum = 0; i<N; i+=np) {
 16      double x = (i + 0.5)/N;
 17      sum += 4 / (1 + x*x);
 18    }
 19    sum /= N;
 20    if (id) {
 21      scanf("%lf", &left);
 22      sum += left;
 23    }
 24    fflush(stdout);
 25    printf("%lf\n", sum);
 26  //  fprintf(stderr, "[%d] %lf\n", id, sum);
 27  }
Es posible establecer un pipe entre diversas réplicas de este programa
para calcular una aproximación a 
. Veamos un ejemplo
de ejecución en pipe:
lhp@nereida:~/Lperl/src/perl_networking/ch2$ gcc pi.c -o pi
lhp@nereida:~/Lperl/src/perl_networking/ch2$ time pi 0 1000000 4 | pi 1 1000000 4 | \
                                                  pi 2 1000000 4 | pi 3 1000000 4
3.141592
real    0m0.026s
user    0m0.070s
sys     0m0.010s
En secuencia:
lhp@nereida:~/Lperl/src/perl_networking/ch2$ time \
              (pi 0 1000000 4;  echo 0 | pi 1 1000000 4 ; echo 0 | pi 2 1000000 4 ;\
               echo 0 | pi 3 1000000 4)
0.785399
0.785398
0.785398
0.785397
real    0m0.042s
user    0m0.040s
sys     0m0.000s
Usando pipes con nombres:
lhp@nereida:~/Lperl/src/perl_networking/ch2$ mkfifo f0 f1 f2
lhp@nereida:~/Lperl/src/perl_networking/ch2$ time ((pi 0 1000000 4 >f0 &);\
     (pi 1 1000000 4 <f0 >f1  &); (pi 2 1000000 4 <f1 >f2 &); (pi 3 1000000 4 <f2))
3.141592
real    0m0.025s
user    0m0.020s
sys     0m0.010s
Escriba un programa Perl que lee/evalúa un fichero de 
configuración describiendo una secuencia de comandos a ejecutar.
Según la opción en la línea de argumentos -p|-n|-s
el programa ejecuta los comandos en pipe, pipe con nombres
o en secuencia. 
Escriba en un módulo UnixProcess::Composition::Simple con funciones genéricas que 
retornen la cadena unix que describe la composición
de los comandos en secuencia, en pipe y en pipe con nombre.
Sigue un ejemplo de lo que podría ser el código de la función 
que implanta los pipes ordinarios:
pp2@nereida:~/src/perl/pipesconnombre$ sed -ne '63,73p' pi_pipenamed_cas.pl | cat -n
 1  sub unixpipe {
 2    my @commands = @_;
 3
 4    my $lastproc = $#commands;
 5    my @cmds = map { "$commands[$_] |" } 0..$lastproc;
 6    our ($a, $b);
 7    my $cmds = reduce { "$a$b" } @cmds;
 8    chop($cmds); # Supress final |
 9
10    return $cmds;
11  }
La función hace uso de  reduce  que se encuentra en  List::Util .
Otra función que puede serle útil al escribir la práctica
es  all   en  List::MoreUtils :
die "All args must be numbers" unless all { /\d+/ and $_ > 0 } @ARGV;
Para llamar a la función unixpipe necesita preparar los comandos
para que incluyan a los argumentos. 
Para el programa de cálculo de 
@commands = map { "$command $_ $nblocks $nprocs" } 0..$nprocs-1;
my $pipe = unixpipe(@commands);
system $pipe or die "Can't execute $pipe";
Utilice IPC::Run3 para la ejecución si está instalado.
Compare los tiempos obtenidos 
usando la función  timethese  del módulo  Benchmark  para las comparaciones.
Cuando entregue la práctica acompañela de todos los ficheros necesarios.
Casiano Rodríguez León
