Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ibraheemdev/firefly

High performance concurrent channels.
https://github.com/ibraheemdev/firefly

Last synced: 28 days ago
JSON representation

High performance concurrent channels.

Awesome Lists containing this project

README

        

# `firefly`

A collection of high performance concurrent channels.

```rust
// create a SPSC channel with a capacity of 2
let (mut tx, mut rx) = firefly::spsc::bounded(2);

task::spawn(async move {
// send a message across asynchronously
tx.send(42).await.unwrap();
});

// receive the message synchronously
assert_eq!(rx.recv_blocking().unwrap(), 42);
```

## Channel Flavors

Firefly provides a variety of channel flavors, optimized for specific use cases:

- [`spsc::bounded`](https://docs.rs/firefly/latest/firefly/spsc/fn.bounded.html)
- [`spsc::unbounded`](https://docs.rs/firefly/latest/firefly/spsc/fn.unbounded.html)
- [`mpsc::bounded`](https://docs.rs/firefly/latest/firefly/mpsc/fn.bounded.html)
- [`mpsc::unbounded`](https://docs.rs/firefly/latest/firefly/mpsc/fn.unbounded.html)
- [`mpmc::bounded`](https://docs.rs/firefly/latest/firefly/mpmc/fn.bounded.html)
- [`mpmc::unbounded`](https://docs.rs/firefly/latest/firefly/mpmc/fn.unbounded.html)

In general, a channel flavor higher up on the list is likely to be more performant
than a more generic one lower down.

---

Bounded channels are created with a bounded capacity; the maximum number of messages
that can be held at a given time:

```rust
// create a channel that can hold at most 8 messages at a time
let (mut tx, mut rx) = firefly::spsc::bounded(8);

task::spawn(async move {
for i in 0..100 {
// send a message, potentially waiting until capacity frees up
tx.send(i).await.unwrap();
}
});

// block until messages are sent
while let Ok(i) = rx.recv_blocking() {
println!("{i}");
}
```

Unbounded channels on the other hand are unlimited in their capacity, meaning that
sending never blocks:

```rust
// create an unbounded channel
let (mut tx, mut rx) = firefly::spsc::unbounded();

task::spawn(async move {
// send an arbitrary amount of messages
for i in 0..10_000 {
tx.send(i).unwrap();
}
});

// block until all messages are sent
while let Ok(i) = rx.recv_blocking() {
println!("{i}");
}
```

## Blocking

Send and receive operations can be performed four different ways:

- Non-blocking (returns immediately with success or failure).
- Asynchronously (blocks the async task).
- Blocking (blocks the thread until the operation succeeds or the channel disconnects).
- Blocking with a timeout (blocks upto a maximum duration of time).

```rust
let (mut tx, mut rx) = firefly::spsc::bounded(4);

thread::spawn(move || {
for _ in 0..3 {
// this can never fail because we never exceed the capacity
tx.try_send(42).unwrap();
}
});

// attempt to receive the message without blocking
match rx.try_recv() {
Ok(x) => assert_eq!(x, 42),
Err(_) => println!("message has not been sent yet")
}

// block until the message is sent
assert_eq!(rx.recv_blocking(), Ok(42));

// block for at most 1 second
match rx.recv_blocking_timeout(Duration::from_secs(1)) {
Ok(x) => assert_eq!(x, 42),
Err(_) => println!("message took too long to send")
}

// spawn a task that receives the message asynchronously
task::spawn(async move {
assert_eq!(rx.recv().await, Ok(42));
});
```

All channels can be used to "bridge" between async and sync code:

```rust
let (mut tx, mut rx) = firefly::spsc::bounded(8);

// send messages synchronously
thread::spawn(move || {
for i in 0..16 {
tx.send_blocking(i).unwrap()
}
});

// receive asynchronously
task::spawn(async move {
while let Ok(i) = rx.recv().await {
println!("{i}");
}
});
```

## Disconnection

When all senders or receivers of a given channel are dropped, the channel is
disconnected. Any attempts to send a message will fail. Any remaining messages
in the channel can be received, but subsequent attempts to receive will also
fail:

```rust
let (mut tx, mut rx) = firefly::spsc::unbounded();

tx.send(1).unwrap();
tx.send(2).unwrap();

// disconnect the sender
drop(tx);

// any remaining messages can be received
assert_eq!(rx.recv().await, Ok(1));
assert_eq!(rx.recv().await, Ok(2));

// subsequent attempts will error
assert_eq!(rx.recv().await, Err(firefly::RecvError));
```