What You’ll Learn
Runtime Integration
Use Tokio with custom executor frameworks
TokioContext
Wrap futures to enter Tokio context on poll
Hybrid Runtimes
Combine multiple async runtimes in one application
Resource Management
Run Tokio drivers on a background thread
Use Cases
You might need a custom executor integration when:- Migrating an existing application to Tokio gradually
- Using a different executor for specific workload characteristics
- Building a custom runtime with specialized scheduling
- Integrating with frameworks that provide their own executors
For most applications, using Tokio’s built-in runtime is recommended. Only use this approach if you have specific requirements that necessitate a custom executor.
Complete Code
How It Works
The example creates a hybrid runtime that combines:- Tokio Runtime - Runs on background threads to handle I/O and timers
- Custom Executor - Runs tasks using
futures::executor::ThreadPool - TokioContext - Bridges the two by entering Tokio context during polling
Code Walkthrough
Initialize the hybrid runtime
The
EXECUTOR is lazily initialized with both a Tokio runtime and a custom thread pool:Lazy::new ensures the runtime is only created once, on first use.Wrap futures with TokioContext
When spawning a task, wrap it with The
TokioContext to automatically enter the Tokio context:handle provides access to the Tokio runtime from any thread.Use Tokio types in the custom executor
Because the future is wrapped with
TokioContext, you can use Tokio types like TcpListener:Key Components
TokioContext
TokioContext is a wrapper that:
- Enters the Tokio context whenever the future is polled
- Allows Tokio I/O and timers to function correctly
- Is transparent - it doesn’t change the future’s output type
Runtime Handle
Handle provides a reference to the Tokio runtime that can be:
- Cloned cheaply
- Sent across threads
- Used to spawn tasks or enter the runtime context
Lazy Initialization
Lazy wrapper ensures thread-safe, one-time initialization of the global executor.
Performance Considerations
Minimal Overhead
TokioContext adds negligible overhead per poll
Shared Resources
Both executors share the same thread pool resources
Single Driver Thread
Only one background thread needed for Tokio drivers
Work Stealing
Tasks can move between executor and Tokio threads
Runtime Configuration
Multi-threaded Runtime
- I/O driver for async networking
- Timer driver for
sleep,timeout, etc. - Work-stealing thread pool
Current Thread Runtime
For single-threaded applications:Advanced Patterns
Spawning from Any Thread
Mixing Executors
Graceful Shutdown
Testing
You can test the example by running:0, which lets the OS choose an available port.
Common Pitfalls
Comparison: Custom vs. Native Runtime
| Feature | Custom Executor | Native Tokio |
|---|---|---|
| Setup Complexity | High | Low |
| Performance | Good | Excellent |
| Memory Usage | Higher (two runtimes) | Lower |
| Maintenance | More complex | Simpler |
| Use Case | Legacy integration | New projects |
When to Use This Pattern
✅ Use custom executor integration when:- Migrating from another async runtime
- Working with existing custom executor code
- Need specific scheduling characteristics
- Building a specialized framework
- Starting a new project (use native Tokio)
- Performance is critical (extra overhead)
- No specific executor requirements
Related Examples
Echo Server
See how to build servers with native Tokio runtime
Chat Server
Explore concurrent task management patterns