Tachyonix

repository·main·Indexed 41 days ago

https://github.com/asynchronics/tachyonix

An extremely high-performance, asynchronous, multi-producer, single-consumer (MPSC) bounded channel for Rust, designed for system simulation and high-throughput workloads. Version 0.3.1 provides async send and receive operations, timeout support, and implements futures_core::Stream for the receiver.

Tokens
1.9K
Snippets
7
Records
10
Agent score
50%

What's inside Tachyonix

  1. Understand the limitations of tachyonix

    main

    Tachyonix is optimized for extreme speed in MPSC use-cases, but this involves specific trade-offs:

    • No Fairness Guarantees: Fairness for blocked senders is not enforced. While the first sender blocked on a full channel is notified first, it may be outrun by another sender that is scheduled sooner. If you require strict fairness, use tokio or futures channels.
    • Capacity Risk: The effective capacity of the channel decreases if blocked senders are "forgotten" (i.e., they were not polled to completion but were not dropped). This can eventually lead to a deadlock. If your application cannot guarantee sender completion, use futures channels.
    • No Zero-Capacity Channels: Rendez-vous channels (zero-capacity) are not supported.
    • Unsafe Primitives: The low-level primitives rely on unsafe code for performance.
  2. Safety and correctness in tachyonix

    main
    Tachyonix prioritizes implementation quality and correctness despite its focus on performance. The library uses Loom for testing low-level concurrency primitives and MIRI for integration tests. However, because it relies on unsafe code, it cannot formally prove the absence of data races. Users should exercise caution when using it in mission-critical software.
  3. Understand channel disconnection behavior

    main

    A tachyonix channel is disconnected automatically when:

    1. All Sender handles are dropped.
    2. The Receiver handle is dropped.
    3. Either Sender::close() or Receiver::close() is called manually.

    Behavior during disconnection:

    • Once disconnected, all subsequent send attempts will return an error.
    • The Receiver can still receive messages that were already in the channel. It will only return a disconnection error (RecvError, RecvTimeoutError::Closed, or TryRecvError::Closed) once the internal queue is completely empty.
  4. How to use tachyonix channels

    main

    Tachyonix provides an asynchronous, multi-producer, single-consumer (MPSC) bounded channel. You can create a channel using tachyonix::channel(capacity), which returns a sender s and a receiver r. The sender can use .send(value).await and the receiver can use .recv().await to communicate asynchronously.

    use tachyonix;
    use futures_executor::{block_on, ThreadPool};
    
    let pool = ThreadPool::new().unwrap();
    
    let (s, mut r) = tachyonix::channel(3);
    
    block_on( async move {
        pool.spawn_ok( async move {
            assert_eq!(s.send("Hello").await, Ok(()));
        });
        
        assert_eq!(r.recv().await, Ok("Hello"));
    });
  5. Send messages with Sender

    main

    The Sender<T> handle allows you to push messages into the channel. You can clone the Sender to allow multiple producers.

    Available methods:

    • try_send(message): Attempts to send a message immediately without waiting. Returns TrySendError<T> if the channel is full or closed.
    • send(message): An async method that waits until capacity is available. Returns SendError<T> if the channel is closed.
    • send_timeout(message, deadline): An async method that waits for capacity or until a deadline (a Future) elapses. Returns SendTimeoutError<T> if the deadline is reached or the channel is closed.
    • close(): Manually closes the channel, preventing further sends. Existing messages can still be received.
    • is_closed(): Checks if the channel is closed.
    // Async send
    s.send("Hello").await.unwrap();
    
    // Non-blocking try_send
    match s.try_send("World") {
        Ok(()) => println!("Sent!"),
        Err(TrySendError::Full(msg)) => println!("Full, kept: {}", msg),
        Err(TrySendError::Closed(msg)) => println!("Closed, kept: {}", msg),
    }
  6. Create a tachyonix channel

    main

    Use tachyonix::channel(capacity) to create a new asynchronous, multi-producer, single-consumer (MPSC) bounded channel. It returns a tuple containing a Sender<T> and a Receiver<T>.

    Note: The function will panic if the requested capacity is 0 or greater than usize::MAX/2 + 1.

    use tachyonix;
    
    let (s, mut r) = tachyonix::channel(3);
  7. Receive messages with Receiver

    main

    The Receiver<T> handle allows you to pull messages from the channel. The receiver can only be used from a single thread (it does not implement Clone).

    Available methods:

    • try_recv(): Attempts to receive a message immediately. Returns TryRecvError if the channel is empty or closed.
    • recv(): An async method that waits until a message is available. Returns RecvError if the channel is closed.
    • recv_timeout(deadline): An async method that waits for a message or until a deadline elapses. Returns RecvTimeoutError if the deadline is reached or the channel is closed.
    • close(): Manually closes the channel. This prevents further sends; it is recommended to follow this with a loop to drain remaining messages.

    Receiver<T> also implements futures_core::Stream, allowing you to use it with stream combinators.

    // Async receive
    match r.recv().await {
        Ok(msg) => println!("Received: {}", msg),
        Err(RecvError) => println!("Channel closed"),
    }
    
    // Using as a Stream
    use futures_util::StreamExt;
    while let Some(msg) = r.next().await {
        println!("Stream msg: {}", msg);
    }
  8. Reference: Sender Error Types

    main

    Errors returned by Sender operations.

    Error TypeContextVariants
    TrySendError<T>try_sendFull(T), Closed(T)
    SendError<T>sendSendError(T) (contains the message)
    SendTimeoutError<T>send_timeoutTimeout(T), Closed(T)
    // TrySendError variants
    pub enum TrySendError<T> {
        Full(T),
        Closed(T),
    }
    
    // SendError
    pub struct SendError<T>(pub T);
    
    // SendTimeoutError variants
    pub enum SendTimeoutError<T> {
        Timeout(T),
        Closed(T),
    }
  9. Reference: Receiver Error Types

    main

    Errors returned by Receiver operations.

    Error TypeContextVariants
    TryRecvErrortry_recvEmpty, Closed
    RecvErrorrecvRecvError (unit struct)
    RecvTimeoutErrorrecv_timeoutTimeout, Closed
    // TryRecvError variants
    pub enum TryRecvError {
        Empty,
        Closed,
    }
    
    // RecvError
    pub struct RecvError;
    
    // RecvTimeoutError variants
    pub enum RecvTimeoutError {
        Timeout,
        Closed,
    }