Module glommio::channels::shared_channel[][src]

Allow data to be transmitted across two tasks in the different executors.

Most useful thread-per-core applications will heavily process data locally to their executor, but at times inter-executor communication is unavoidable (if you never communicate inter-executors, you may consider just using independent processes!)

Whenever you need to send data across two executors you can use the shared_channel. This channel is a fully lockless single-producer-single-consumer channel, unlike the standard library channel, which is multi-producer and need locks for synchronization. That means that to wire N executors to each other you will have to create O(N^2) channels.

The channels are also not bidirectional, so for full bidirectional communication you will need pairs of channels.

True to the spirit of our library the shared_channel is not created or wired automatically among executors. You can have executors that work as sinks and never respond back, other executors that are not really connected to anybody, cliques of executors, you name it.

However, note that connecting a channel will involve a blocking operation as we need to synchronize and exchange information between peers. That can block the executor, although in practice that will only happen if it races with the creation of a new executor. Because of that, The best performance pattern when using shared channels is to create both the executors and channels early, connect the channels as soon as they start, and keep them alive.

Data that goes into the channels need to be Send, as well as the channels themselves (otherwise you would not be able to really pass them along to the actual executors). But to prevent accidental use from multiple producers, the channel endpoints have to be connected before using: Connecting consumes the endpoint, transforming a SharedSender into a ConnectedSender and a SharedReceiver into a ConnectedReceiver so although you can pass one of the ends of the channel to multiple executors, you can only connect in one of them. The connected channel itself is not Send nor Sync so once connected they are stuck in an executor.

The communication between sender and receiver is broken when one of them goes out of scope. They however behave differently:

Examples

use glommio::{channels::shared_channel, Local, LocalExecutorBuilder};

// creates both ends of the channel. This is done outside the executors
// and we will not pass the sender to ex1 and the receiver to ex2
let (sender, receiver) = shared_channel::new_bounded(1);

let ex1 = LocalExecutorBuilder::new()
    .spawn(move || async move {
        // Before using we have to connect. Connecting this endpoint
        // binds it this executor as the connected endpoint is not Send.
        let sender = sender.connect().await;
        // Channel has room for 1 element so this will always succeed
        sender.try_send(100).unwrap();
    })
    .unwrap();

let ex2 = LocalExecutorBuilder::new()
    .spawn(move || async move {
        // much like the sender, the receiver also needs to be connected
        let receiver = receiver.connect().await;
        let x = receiver.recv().await.unwrap();
        assert_eq!(x, 100);
    })
    .unwrap();

ex1.join().unwrap();
ex2.join().unwrap();

Structs

ConnectedReceiver

The ConnectedReceiver is the receiving end of the Shared Channel.

ConnectedSender

The ConnectedReceiver is the sending end of the Shared Channel.

SharedReceiver

The SharedReceiver is the receiving end of the Shared Channel. It implements Send so it can be passed to any thread. However it doesn’t implement any method: before it is used it must be changed into a ConnectedReceiver, which then makes sure it will be used by at most one thread.

SharedSender

The SharedSender is the sending end of the Shared Channel. It implements Send so it can be passed to any thread. However it doesn’t implement any method: before it is used it must be changed into a ConnectedSender, which then makes sure it will be used by at most one thread.

Functions

new_bounded

Creates a a new shared_channel returning its sender and receiver endpoints.