Linch
Linch is a high-performance async/sync channel library for Rust that prioritizes simplicity and efficiency. While performance is important, Linch's primary focus is providing a clean, straightforward implementation that's easy to understand and use, with seamless communication between sync and async contexts.
Etymology: The name "linch" is short for "lined channel" - like a concrete-lined channel that provides a smooth, reliable pathway for water flow. Similarly, Linch provides a smooth, reliable pathway for data flow between different parts of your application.
Key Features
- ๐ Mixed Sync/Async: Send and receive both synchronously and asynchronously
- ๐ Cross-Context Communication: Seamlessly bridge sync and async code without blocking
- ๐ฏ Simple Design: Clean, minimal API that's easy to understand and integrate
- โก High Performance: Optimized for throughput and low latency
- ๐ Select Operations: Support for selecting over multiple channels
- ๐ฆ Two Implementations: Choose between the main channel and schannel variants
- ๐งต Thread Safe: Full support for multi-producer, multi-consumer scenarios
Quick Start
Add this to your Cargo.toml:
[]
= "0.1"
Basic Usage
use bounded;
// Create a bounded channel with capacity 10
let = bounded;
// Send synchronously
sender.send.unwrap;
// Receive synchronously
let value = receiver.recv.unwrap;
assert_eq!;
Async Usage
use bounded;
async
Two Channel Implementations
Linch provides two channel implementations to suit different use cases:
1. Main Channel (linch::channel)
The primary implementation focuses on simplicity and correctness with efficient async handling:
use bounded;
let = channel;
When to use:
- โ General-purpose applications
- โ When you want proper async/await integration
- โ Applications with mixed sync/async workloads
- โ Bridging sync and async contexts (e.g., sync threads communicating with async tasks)
- โ When CPU efficiency matters during idle periods
- โ Production applications requiring reliability
Characteristics:
- Uses proper waker-based async coordination
- CPU-efficient when channels are idle
- Slightly more complex internals for better async integration
- Supports select operations
2. SChannel (linch::schannel)
A high-throughput implementation optimized for maximum performance:
use schannel;
let = with_capacity;
When to use:
- โก Benchmarking against other channel implementations
- โก When maximum throughput is critical
- โก Applications that keep channels busy continuously
Characteristics:
- Uses active polling for async operations
- Optimized for scenarios where channels rarely stay empty
- Higher CPU usage during async operations
- Maximum performance for high-throughput scenarios
Examples
Cross-Context Communication
One of Linch's key strengths is enabling seamless communication between sync and async contexts:
use bounded;
use thread;
async
You can also send from async contexts to sync contexts:
use bounded;
use thread;
async
Select Operations
use ;
async
Stream Integration
The schannel implementation supports conversion to async streams:
use schannel;
use StreamExt;
async
Performance Characteristics
Linch is designed with performance in mind, but simplicity comes first. The implementations are:
- Zero-copy where possible
- Optimized for both single and multi-threaded scenarios
- Benchmarked against other popular Rust channel libraries
Benchmarking
The crate includes comprehensive benchmarks comparing against other channel implementations:
# Run all benchmarks
# Run specific benchmark categories
See the benchmark guide for detailed performance analysis.
Design Philosophy
Linch prioritizes:
- Simplicity: Clean, understandable code that's easy to maintain and debug
- Cross-Context Communication: Seamless bridging between sync and async code without complexity
- Correctness: Proper async/await integration and memory safety
- Performance: High throughput and low latency, but not at the expense of simplicity
- Flexibility: Support for both sync and async patterns in the same channel
The goal is to provide a channel implementation that's both easy to use and fast enough for most applications, with particular focus on making sync/async interoperability effortless.
API Reference
Main Channel Functions
bounded(capacity)- Create a bounded channelSender::send(item)- Send synchronouslySender::send_async(item)- Send asynchronouslyReceiver::recv()- Receive synchronouslyReceiver::recv_async()- Receive asynchronously
SChannel Functions
schannel::bounded(capacity)- Create a high-throughput channelSender::send_async(item)- Send asynchronously with active pollingReceiver::recv_async()- Receive asynchronously with active pollingReceiver::into_stream()- Convert to async stream
Select Operations
Both the main channel and schannel support select operations:
Main Channel Select:
Select::new()- Create a new select operationSelect::recv(receiver)- Add receiver to selectSelect::select()- Wait for any operation to complete
SChannel Select:
schannel::Select::new()- Create a new select operationschannel::Select::recv(receiver)- Add receiver to selectschannel::Select::send(sender)- Add sender to selectschannel::Select::select()- Wait for any operation to completeschannel::Select::try_select()- Non-blocking selectschannel::Select::select_timeout(timeout)- Select with timeout
Error Handling
Both implementations use standard Rust error types:
SendError<T>- Returned when all receivers are droppedRecvError- Returned when all senders are droppedSendTimeoutError<T>- Returned on send timeoutRecvTimeoutError- Returned on receive timeout
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. The project values:
- Code clarity over micro-optimizations
- Comprehensive tests for all features
- Good documentation with examples
- Benchmark coverage for performance-critical changes
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built on top of the excellent crossbeam-channel library
- Inspired by Go's channels and Rust's async ecosystem
- The concrete-lined channel metaphor reflects the library's goal of providing reliable, efficient data pathways
- Thanks to the Rust community for feedback and contributions