lunes, julio 20, 2009

Resolviendo ejercicios de MPI (y tambien en erlang) Parte 4

Sigo molestando con estos problemas, me salte uno que no me daba ganas de resolver y pase al siguiente:

http://www.mcs.anl.gov/research/projects/mpi/tutorial/mpiexmpl/src/ring/C/main.html

Write a program that takes data from process zero and sends it to all of the other processes by sending it in a ring. That is, process i should receive the data and send it to process i+1, until the last process is reached.

la solucion en C salio bastante facil haciendo copypasta de los problemas anteriores y sorprendentemente en este caso los otros procesos si imprimieron a la consola:

#include <stdio.h>
#include <mpi.h>

int main (int argc, char** argv) {
int rank, size, value, i;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */

do {
if(rank == 0) {
printf("give me a value: ");
scanf("%d", &value);
fflush(stdout);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
else{
MPI_Recv(&value, 1, MPI_INT, rank - 1, 1, MPI_COMM_WORLD, &status);
printf("process %d received %d\n", rank, value);
if(rank + 1 < size) {
printf("sending to %d\n", rank + 1, value);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
fflush(stdout);
}
} while(value >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}


la solucion en erlang (tambien robando del ejercicio anterior):

-module(ej5).
-export([run/1]).

run(Total) ->
NextPid = spawn_listeners(Total),
get_values(NextPid).

spawn_listeners(Count) -> spawn_listeners(Count, none).

spawn_listeners(0, NextPid) -> NextPid;
spawn_listeners(Count, LastPid) ->
NextPid = spawn(fun() -> listener(LastPid) end),
spawn_listeners(Count - 1, NextPid).

listener(NextPid) ->
receive
Int ->
io:format("process ~p received ~p~n", [self(), Int]),
if
NextPid /= none ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! Int;
true -> ok
end,
if
Int >= 0 -> listener(NextPid);
true ->
io:format("negative value, closing ~p~n", [self()])
end
end.

get_value(Message, ConversionFun) ->
case io:get_line(Message) of
{error, Reason} -> {error, Reason};
eof -> {error, eof};
Value -> ConversionFun(Value)
end.

get_values(NextPid) ->
case get_value("give me an int value (negative to quit): ", fun(Val) -> string:to_integer(Val) end) of
{error, Reason} ->
io:format("error reading int value (~p)~n", [Reason]),
get_values(NextPid);
{IntValue, _Rest} ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! IntValue,
if
IntValue >= 0 -> get_values(NextPid);
true -> io:format("negative value, closing~n")
end
end.


ejemplo de salida:

$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5 (abort with ^G)
1> c(ej5).
{ok,ej5}
2> ej5:run(3).
give me an int value (negative to quit): 3
sending to <0.40.0>
process <0.40.0> received 3
sending to <0.39.0>
process <0.39.0> received 3
sending to <0.38.0>
process <0.38.0> received 3
give me an int value (negative to quit): asd
error reading int value (no_integer)
give me an int value (negative to quit): 42
sending to <0.40.0>
process <0.40.0> received 42
sending to <0.39.0>
process <0.39.0> received 42
sending to <0.38.0>
process <0.38.0> received 42
give me an int value (negative to quit): -1
sending to <0.40.0>
negative value, closing
process <0.40.0> received -1
sending to <0.39.0>
ok
negative value, closing <0.40.0>
process <0.39.0> received -1
sending to <0.38.0>
negative value, closing <0.39.0>
process <0.38.0> received -1
negative value, closing <0.38.0>

3 comentarios:

Agüero, Santiago Alejandro dijo...

¡Hola Mariano, cómo estás! Muy interesante los ejercicios que estás resolviendo. ¿Erlang es un lenguaje de programación tipo Ruby?

¡Saludos!

luismarianoguerra dijo...

Buenas, no erlang es un lenguaje funcional orientado a la concurrencia y alta disponibilidad. En criollo significa que los programas se diseñan en base a funciones que intercambian mensajes.

no le pasa muy cerca a ruby ni a ninguno similar ya que no es orientado a objetos, de hecho no tiene variables como normalmente las conocemos tampoco ya que una variable puede ser asignada una sola vez.

Para agregarle diversión no tiene primitivas de iteracion como for y while (aunque pueden ser simuladas con recursion).

todo esto es asi para permitir escribir sistemas de alta concurrencia sin problemas como deadlocks, race conditions y problemas similares que nos trae aparejado un lenguaje con estado global o mejor dicho con shared memory.

Agüero, Santiago Alejandro dijo...

Muy interesante. Gracias por la explicación, cuando pueda experimento un poco con el mismo.

¡Saludos! [Por cierto, estuvo buena la charla que diste la otra vez en Intel, fui parte del grupo de la profe Blanca Carrizo]

Seguidores

Archivo del Blog