Non Blocking Channel Operations in Julia

Basic sends and receives on channels are blocking. However, we can use select with an else clause to implement non-blocking sends, receives, and even non-blocking multi-way selects.

using Printf

function main()
    messages = Channel{String}(0)
    signals = Channel{Bool}(0)

    # Here's a non-blocking receive. If a value is
    # available on `messages` then `select` will take
    # the `messages` case with that value. If not
    # it will immediately take the `else` case.
    @select begin
        msg = take!(messages) => @printf("received message %s\n", msg)
        else => println("no message received")
    end

    # A non-blocking send works similarly. Here `msg`
    # cannot be sent to the `messages` channel, because
    # the channel has no buffer and there is no receiver.
    # Therefore the `else` case is selected.
    msg = "hi"
    @select begin
        put!(messages, msg) => @printf("sent message %s\n", msg)
        else => println("no message sent")
    end

    # We can use multiple cases above the `else`
    # clause to implement a multi-way non-blocking
    # select. Here we attempt non-blocking receives
    # on both `messages` and `signals`.
    @select begin
        msg = take!(messages) => @printf("received message %s\n", msg)
        sig = take!(signals) => @printf("received signal %s\n", sig)
        else => println("no activity")
    end
end

main()

When you run this program, it will output:

no message received
no message sent
no activity

In Julia, we use the Channel type to create channels. The @select macro is used to implement non-blocking operations on channels, similar to Go’s select statement. The else clause in Julia’s @select serves the same purpose as Go’s default case.

The take! function is used to receive from a channel, while put! is used to send to a channel. These operations are wrapped in the @select macro to make them non-blocking.

Note that Julia’s channel operations are generally blocking by default, but the @select macro allows us to implement non-blocking behavior, similar to Go’s select statement with a default case.