Non Blocking Channel Operations in Erlang

In Erlang, we can implement non-blocking channel operations using the receive statement with a timeout. Here’s how we can translate the Go example:

-module(non_blocking_channel_operations).
-export([main/0]).

main() ->
    Messages = spawn(fun() -> message_loop([]) end),
    Signals = spawn(fun() -> signal_loop([]) end),

    % Here's a non-blocking receive. If a message is
    % available, it will be received. If not, the 
    % after clause will be executed immediately.
    receive
        {message, Msg} ->
            io:format("received message ~p~n", [Msg])
    after 0 ->
        io:format("no message received~n")
    end,

    % A non-blocking send works similarly. Here we attempt
    % to send a message, but if the receiver is not ready,
    % the after clause is executed immediately.
    Msg = "hi",
    Messages ! {self(), Msg},
    receive
        ok ->
            io:format("sent message ~p~n", [Msg])
    after 0 ->
        io:format("no message sent~n")
    end,

    % We can use multiple patterns above the after clause
    % to implement a multi-way non-blocking select. Here we
    % attempt non-blocking receives on both Messages and Signals.
    receive
        {message, Msg2} ->
            io:format("received message ~p~n", [Msg2]);
        {signal, Sig} ->
            io:format("received signal ~p~n", [Sig])
    after 0 ->
        io:format("no activity~n")
    end.

message_loop(Messages) ->
    receive
        {From, Msg} ->
            From ! ok,
            message_loop([Msg|Messages])
    end.

signal_loop(Signals) ->
    receive
        {From, Sig} ->
            From ! ok,
            signal_loop([Sig|Signals])
    end.

To run the program:

$ erlc non_blocking_channel_operations.erl
$ erl -noshell -s non_blocking_channel_operations main -s init stop
no message received
no message sent
no activity

In this Erlang version, we use processes to simulate channels. The spawn function creates new processes that run the message_loop and signal_loop functions. These functions act as our “channels”, storing messages and signals respectively.

The receive statement in Erlang is used to receive messages. By adding an after 0 -> clause, we make the receive non-blocking. If no message is available immediately, the code in the after clause is executed.

For sending messages, we use the ! operator to send a message to a process. We then immediately try to receive an acknowledgement with a timeout of 0, making it non-blocking.

The multi-way select is implemented using multiple patterns in the receive statement, followed by an after 0 -> clause for the default case.

This Erlang code demonstrates the concept of non-blocking operations on channels, albeit using Erlang’s process-based concurrency model rather than Go’s channels.