sends don't block, right?

Joe Armstrong joe@REDACTED
Wed Feb 25 11:45:26 CET 2004


On Tue, 24 Feb 2004, Shawn Pearce wrote:

> Ok, colo(u)r me stupid now (borrowed phrase, sorry!):
> 
> ! doesn't block, right?
> 
> If I do something foolish like this:
> 
> 	never_end() ->
> 		Pid = spawn(fun() -> receive foo -> ok end),
> 		do_loop(Pid).
> 
> 	do_loop(Pid) ->
> 		Pid ! bar,
> 		io:format("still going, just like the bunny~n", []),
> 		do_loop(Pid).
> 
> will the parent ever stop because the child's message buffer is full?
> 

  That depends on the relative rates that the produce and consumer run
at.

  If you consume  messages faster than you produce  them then you will
be ok - otherwise you'll be screwed.

  In the early  days of Erlang I  used to write a mixture  of RPCs and
casts pretty much as the  problem dictated - occasionally I'd run into
buffer overrun  problems (such  as the kind  that would occur  in your
example) and  so I went  over to the  synced RPC style  of programming
where buffer overflow can't occur.

  More recently I have returned  to my original style of programming -
Asynchronous sends  are find - but you  need to take a  little care to
make sure you can't go into infinite send loops (like you program) and
that if you are doing a load of asynchronous sends then you interleave
the odd RPC to synchronize things again.

  If  you do  a whole  bundle of  asynchronous sends  and then  an RPC
things will  get synchronized  at the RPC  and the buffers  should not
saturate - this is of course only true between pairs of processes.

  I now love my !! operator - and program clients with

	A ! B         and 
	Val = A !! B

  operators

  I program the servers like this:

	receive
	    {replyTo, Pid, ReplyAs, Q} ->
		...
		Pid ! {ReplyAs, Val}
		...
	    Msg -> 	
		...

  And don't use any stub routines (horrors).

  Robert  (Virding)  first  programmed  the  I/O  routines  with  this
replyTo-replyAs style - it's very nice ...

  Now I don't write interface  functions that abstract out the message
passing interface. That way I can clearly "see" the message passing.

  If you use !!  at the top  level of your code then you can "see" the
RPC - my brain goes (RPC this  might be slow - take care, and RPC this
will synchronize any outstanding asynchronous  message) - so I can see
what I'm doing.

  Burying this *inside*  a stub function which hides  the RPC makes me
loose sight of the important fact that we are doing an RPC. If the RPC
is  "off site"  (ie  we do  an  RPC on  a remote  node)  then we  have
abstracted  away  from  the  single  most important  detail  that  the
programmer should no about.

  Non-local RPCs cause great performance hits.

  When I see this in my code:

	Pid @ Node !! X

  I think <<danger very slow>>

  with

	Pid !! X

  I think <<possibly slow take care>>

  but

	X ! Y

  I thing <<ok but I'll need to synchronize later>>

  Hiding  this  essential  detail  in  a  stub  routine  seems  to  be
abstracting away  from the one essential  detail that we  need to know
about when writing distributed programs.

  /Joe



> Basically, I'm asking if Erlang will let the parent in this case run
> the VM out of memory before making the parent freeze.  Clearly one should
> never write this code, but I'm trying to setup an async-send for my
> serial driver that will "never" block the caller, as apposed to the
> blocking send which makes sure the data was delivered to the endpoint
> before returning.
> 
> The only reason I'm concerned here is the caller could lock up if it
> gets blocked and hardware or software flow control breaks down due to
> link failure.
> 
> With most serial protocols I wouldn't see the need to buffer more than
> a few hundred KB of data, and the port driver already has buffers deep
> enough to handle that, so in theory, port_command/2 should never block.
> I just want to keep from blocking up the application, if the application
> so desires.
> 
> 




More information about the erlang-questions mailing list