Skip to main content
The custom executor example demonstrates how to use Tokio’s I/O and timer capabilities with any executor, not just the Tokio runtime. This is useful when you need to integrate Tokio into an existing application that uses a different async runtime or executor.

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:
  1. Tokio Runtime - Runs on background threads to handle I/O and timers
  2. Custom Executor - Runs tasks using futures::executor::ThreadPool
  3. TokioContext - Bridges the two by entering Tokio context during polling

Code Walkthrough

1

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.
2

Wrap futures with TokioContext

When spawning a task, wrap it with TokioContext to automatically enter the Tokio context:
The handle provides access to the Tokio runtime from any thread.
3

Use Tokio types in the custom executor

Because the future is wrapped with TokioContext, you can use Tokio types like TcpListener:
4

Block on completion

The example uses futures::executor::block_on to wait for the task to complete:
This demonstrates that you can mix and match different executor functions.

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

The 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

The 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

This creates a full multi-threaded runtime with:
  • I/O driver for async networking
  • Timer driver for sleep, timeout, etc.
  • Work-stealing thread pool

Current Thread Runtime

For single-threaded applications:
Use new_current_thread() if your custom executor already provides multi-threading.

Advanced Patterns

Spawning from Any Thread

Mixing Executors

Graceful Shutdown

Testing

You can test the example by running:
You should see output like:
The port number will be different each time because we bind to port 0, which lets the OS choose an available port.

Common Pitfalls

Don’t forget to enable drivers
Don’t drop the runtime handleThe Handle must live as long as tasks are using Tokio features. Store it in a long-lived location.

Comparison: Custom vs. Native Runtime

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
❌ Don’t use it when:
  • Starting a new project (use native Tokio)
  • Performance is critical (extra overhead)
  • No specific executor requirements

Echo Server

See how to build servers with native Tokio runtime

Chat Server

Explore concurrent task management patterns

Further Reading

For most applications, stick with Tokio’s native runtime. Only use custom executors when you have a specific need that justifies the added complexity.