Crate kanal

source ·
Expand description

Kanal

The fast sync and async channel that Rust deserves!

Crates.io Documentation MIT licensed

What is Kanal

The Kanal library is a Rust implementation of channels of the CSP (Communicating Sequential Processes) model, designed to assist programmers in creating efficient concurrent programs. This library provides multi-producer and multi-consumer channels with advanced features and lock-free one-shot channels that only allocate the size of a pointer in the heap, allowing for fast communication. The library has a focus on unifying message passing between synchronous and asynchronous portions of Rust code through a combination of synchronous and asynchronous APIs while maintaining high performance.

Why Kanal is faster?

  1. Kanal employs a highly optimized composite technique for the transfer of objects. When the data size is less than or equal to the pointer size, it utilizes serialization, encoding the data as the pointer address. Conversely, when the data size exceeds the pointer size, the protocol employs a strategy similar to that utilized by the Golang programming language, utilizing direct memory access to copy objects from the sender’s stack or write directly to the receiver’s stack. This composite method not only eliminates unnecessary pointer access but also eliminates heap allocations for bounded(0) channels.
  2. Kanal utilizes a specially tuned mutex for its channel locking mechanism, made possible by the predictable internal lock time of the channel. That said it’s possible to use Rust standard mutex with the std-mutex feature and Kanal will perform better than competitors with that feature too.
  3. Utilizing Rust high-performance compiler and powerful LLVM backend with highly optimized memory access and deeply thought algorithms.

Why use Kanal?

  • Kanal is fast and efficient in communication
  • Kanal can communicate in both sync and async and even between sync and async by providing methods to transform sender/receiver to other API.
  • Kanal provides cleaner API in comparison with other rust libraries
  • Similar to Golang you have access to the Close function and you can broadcast the close signal from any instance of the channel, to close the channel for both sides.
  • Kanal provides high-performance MPMC channels and lock-free one-shot channels in one package.

Why not use Kanal?

  • Kanal developers are trying their best to audit the small codebase of Kanal and make sure there is no undefined behavior. Kanal is using Unsafe. If you are not ok with that in your project we suggest using safe-only alternatives.

Benchmark Results

Results are based on how many messages can be passed in each scenario per second.

Test types:
  1. Seq is sequentially writing and reading to a channel in the same thread.
  2. SPSC is one receiver, and one sender and passing messages between them.
  3. MPSC is multiple sender threads with only one receiver.
  4. MPMC is multiple senders and multiple receivers communicating through the same channel.
Message types:
  1. usize tests are transferring messages of size hardware pointer.
  2. big tests are transferring messages of 8x the size of the hardware pointer.

N/A means that the test subject is unable to perform the test due to its limitations, Some of the test subjects don’t have implementation for size 0 channels, MPMC or unbounded channels.

Machine: AMD Ryzen Threadripper 2950X 16-Core Processor
Rust: rustc 1.66.1 (90743e729 2023-01-10)
Go: go version go1.19.5 linux/amd64
OS (uname -a): Linux 5.15.0-58-generic #64~20.04.1-Ubuntu SMP Fri Jan 6 16:42:31 UTC 2023 x86_64
Date: Jan 25, 2023

Benchmark codes

Benchmarks

Why async outperforms sync in some tests?

In certain tests, asynchronous communication may exhibit superior performance compared to synchronous communication. This can be attributed to the context-switching performance of libraries such as tokio, which, similar to Golang, utilize context-switching within the same thread to switch to the next coroutine when a message is ready on a channel. This approach is more efficient than communicating between separate threads. This same principle applies to asynchronous network applications, which generally exhibit better performance compared to synchronous implementations. As the channel size increases, one may observe improved performance in synchronous benchmarks, as the sending threads are able to push data directly to the channel queue without requiring awaiting blocking/suspending signals from receiving threads.

Structs

AsyncReceiver is receiving side of the channel in async mode. Receivers can be cloned and produce receivers to operate in both sync and async modes.
Sending side of the channel with async API. It’s possible to convert it to sync Sender with as_sync, to_sync or clone_sync based on software requirement.
OneshotAsyncReceiver<T> is the receiver side of oneshot channel that can receive a single message asynchronously. It can be converted to OneshotReceiver<T> by calling Self::to_sync. Receiving a message is achievable with Self::recv which returns a future that should be polled to receive the message.
OneshotAsyncSender<T> is the sender side of oneshot channel that can send a single message asynchronously. It can be converted to OneshotSender<T> by calling Self::to_sync. Sending a message is achievable with Self::send which returns a future that should be polled until transfer is done.
Error type for oneshot channel receive failed operation
Oneshot channel receive future that asynchronously receives data from oneshot sender
OneshotReceiver<T> is the receiver side of oneshot channel that can receive a single message. It can be converted to async OneshotAsyncReceiver<T> by calling Self::to_async. Receiving a message is achievable with Self::recv.
Oneshot channel send future that asynchronously sends data to the oneshot receiver. returns Ok(()) and in case of failure it returns back the sending object as Err(T).
OneshotSender<T> is the sender side of oneshot channel that can send a single message. It can be converted to async OneshotAsyncSender<T> by calling Self::to_async. Sending a message is achievable with Self::send.
Receive future to receive an object from the channel asynchronously It must be polled to perform receive action
Receive stream
Receiving side of the channel in sync mode. Receivers can be cloned and produce receivers to operate in both sync and async modes.
Send future to send an object to the channel asynchronously It must be polled to perform send action
Sending side of the channel with sync API. It’s possible to convert it to async AsyncSender with as_async, to_async or clone_async based on software requirement.

Enums

Error type for channel receive operations without timeout
Error type for channel receive operations with timeout
Error type for channel send operations without timeout
Error type for channel send operations with timeout

Functions

Creates a new sync bounded channel with the requested buffer size, and returns Sender and Receiver of the channel for type T, you can get access to async API of AsyncSender and AsyncReceiver with to_sync, as_async or clone_sync based on your requirements, by calling them on sender or receiver.
Creates a new async bounded channel with the requested buffer size, and returns AsyncSender and AsyncReceiver of the channel for type T, you can get access to sync API of Sender and Receiver with to_sync, as_async or clone_sync based on your requirements, by calling them on async sender or receiver.
Creates new oneshot channel and returns the OneshotSender<T> and OneshotReceiver<T> for it.
Creates new oneshot channel and returns the async OneshotAsyncSender<T> and OneshotAsyncReceiver<T> for it.
Creates a new sync unbounded channel, and returns Sender and Receiver of the channel for type T, you can get access to async API of AsyncSender and AsyncReceiver with to_sync, as_async or clone_sync based on your requirements, by calling them on sender or receiver.
Creates a new async unbounded channel, and returns AsyncSender and AsyncReceiver of the channel for type T, you can get access to sync API of Sender and Receiver with to_sync, as_async or clone_sync based on your requirements, by calling them on async sender or receiver.