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