jd e ([info]jkndrkn) wrote,
@ 2008-02-23 11:10:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Current music:Radiohead - Videotape

MPI versus Erlang - A comparison of two message-passing implementations
Anyone that has written a concurrent application knows that when two threads of execution share resources, programs become difficult to develop and debug. Unreliable locks and mutexes must be used, and juggling threads becomes painful. This is why message passing is a superior technique. Similarly to purely functional programming, message passing strives to reduce the sharing of state. In functional programming, a function has inputs and outputs and does not modify any variables outside the scope of the function during its execution. In message passing, a thread of execution has similar inputs and outputs and does not modify any value outside of its reserved memory block.

Here is an example that illustrates the message-passing implementation in MPI, an extension for C. Two threads of execution are created at execution time, and one thread sense a message to the other, which is then responsible for printing that message.

   1 #include <mpi.h>
   2 
   3 int main(int argc, char *argv[]) {
   4     int rank, size, source, dest, tag, message;
   5 
   6     MPI_Init(&argc, &argv);
   7     MPI_Status status;
   8     MPI_Comm_size(MPI_COMM_WORLD, &size);
   9     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  10 
  11     source, tag = 0;
  12     dest = 1;
  13 
  14     if (rank == 0) {
  15         message = 1234;
  16         MPI_Send(
  17             &message, 1, MPI_INT,
  18             dest, tag, MPI_COMM_WORLD
  19         );
  20     }
  21     else {
  22         MPI_Recv(
  23             &message, 1, MPI_DOUBLE,
  24             source, tag, MPI_COMM_WORLD, &status
  25         );
  26         printf("Received message: %d\n", message);
  27     }
  28 
  29     MPI_Finalize();
  30     return 0;
  31 }

  1> make
  /usr/bin/mpicc -o send_recv send_recv.c
  2> srun -N 2 ./send_recv
  Received message: 1234

Here is the same example in Erlang:
   1 -module(send_recv).
   2 -export([send/0, recv/0]).
   3 
   4 send() ->
   5     Pid = spawn(fun recv/0),
   6     Message = 1234,
   7     Pid ! Message.
   8 
   9 recv() ->
  10     receive
  11         Message ->
  12             io:format("Received message: ~p~n", [Message])
  13     end.

  1> c(send_recv).
  {ok,send_recv}
  2> send_recv:send().
  Received message: 1234
  1234

I know which I would rather code in ;]

To be fair, MPI is designed for massively scalable high-performance computing applications. If one needed to parallelize an application across a thousand-core supercompute cluster, Erlang would not be usable. Further, Erlang's multi-core support is limited to SMP machines, whereas MPI can operate on both SMP machines and clusters.


(15 comments) - (Post a new comment)

libtask!
[info]node
2008-02-24 10:10 am UTC (link)
Cooperative, single-core:

#include <stdio.h>
#include <stdlib.h>

#include "task.h"

#define STACKSIZE 16384

int buffer;

void sender(void *arg)
{
  Channel *c = arg;

  chansendul(c, 1234);
}

void receiver(void *arg)
{
  Channel *c = arg;
  int number;

  number = chanrecvul(c);
  printf("%d\n", number);
}

void taskmain(int argc, char **argv)
{
  Channel *c;

  c = chancreate(sizeof(unsigned long), buffer);

  taskcreate(sender, c, STACKSIZE);
  taskcreate(receiver, c, STACKSIZE);
}

(Reply to this)

scheme48!
[info]node
2008-02-24 10:19 am UTC (link)

(define (two-threads)
  (let ((c (make-channel)))
    ;; receiver
    (spawn (lambda ()
             (display "got ")
             (display (receive c))
             (newline)))
    ;; sender
    (spawn (lambda ()
             (send c 1234)))))

(Reply to this) (Thread)

Re: scheme48!
[info]node
2008-02-24 10:20 am UTC (link)
You probably need to do

,open threads
,open rendezvous-channels

before running that.

(Reply to this) (Parent)


[info]jkndrkn
2008-02-24 05:42 pm UTC (link)
This one looks nice.

Are they green threads? Are they mapped by the run-time to the multiple cores of an SMP system? Can the code be compiled to native machine code to increase performance?

(Reply to this) (Parent)(Thread)


[info]node
2008-02-24 07:25 pm UTC (link)
Yes, no, and no. Or maybe "not yet" for the last one.

(Reply to this) (Parent)(Thread)


[info]jkndrkn
2008-02-24 07:39 pm UTC (link)
Ah, if only all n's were y's. I would have rather used something Lispy than having to learn Erlang's syntax.

(Reply to this) (Parent)(Thread)


[info]node
2008-02-25 05:17 am UTC (link)
There's termite.

(Reply to this) (Parent)


[info]anikosijyv
2008-07-17 05:18 am UTC (link)
From John Kerry, they get a "yes-no-maybe" bowl of mush that can only encourage our enemies and confuse our friends.

(Reply to this) (Parent)

limbo! (ugly)
[info]node
2008-02-24 10:45 am UTC (link)

implement passmsg;

include "sys.m";
include "draw.m";

passmsg: module
{
    init: fn(nil: ref Draw->Context, nil: list of string);
};

sys: Sys;
intchan: chan of int;

init(nil: ref Draw->Context, nil: list of string)
{
    sys = load Sys Sys->PATH;

    intchan = chan of int;
    spawn sender(intchan);
    spawn receiver(intchan);
}

sender(ic: chan of int)
{
    ic <-= 1234;
}

receiver(ic: chan of int)
{
    number: int;

    number =<- ic;
    sys->print("got %d\n", number);
}

(Reply to this)

absurdness!
[info]node
2008-02-24 11:27 am UTC (link)

$ mknod chan p
$ function sender { (echo 1234 > chan &) }
$ function receiver { cat < chan; }
$ sender
$ receiver

(Reply to this) (Thread)

Re: absurdness!
[info]node
2008-02-24 11:40 am UTC (link)
works over nfs!

(Reply to this) (Parent)


[info]jkndrkn
2008-02-24 06:43 pm UTC (link)
This is scary.

(Reply to this) (Parent)

yet more absurdity!
[info]node
2008-02-24 11:39 am UTC (link)
sender:

#!/usr/bin/env python

import boto

conn = boto.connect_sqs()
q = conn.create_queue('absurd2')
m = boto.sqs.message.Message()
m.set_body('1234')
rs = q.write(m)
receiver:

#!/usr/bin/env python

import boto

conn = boto.connect_sqs()
q = conn.get_queue('absurd2')
rs = q.get_messages()
print int(rs[0].get_body())
# be kind, rewind
q.delete_message(rs[0])
conn.delete_queue(q)

(Reply to this) (Thread)


[info]jkndrkn
2008-02-24 06:46 pm UTC (link)
Interesting, but more akin to a client-server producer/consumer model. I remember writing a file transfer protocol that could recuperate from packet loss for a course in networking this way. Of course, I was required to do it in Java. The Python approach illustrated here seems much cleaner.

(Reply to this) (Parent)

thank you
(Anonymous)
2008-03-26 05:15 pm UTC (link)
thanks much, brother

(Reply to this)


(15 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…