Skip to content

mstampfer/Tokio_Tutorial_Patterns_and_Use_Cases

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

31 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tokio Tutorial Patterns and Use Cases

This repository is a collection of Tokio (Rust async runtime) patterns and examples

Relationship to the Official Tokio Tutorial

This repository is structured to complement and extend the official Tokio tutorial. While the tutorial provides foundational concepts and introductory examples, this collection offers:

  • Additional patterns and use-cases for each tutorial section
  • Deeper explanations with more detailed breakdowns of how mechanisms work
  • Extended examples covering edge cases and advanced scenarios
  • Production-ready patterns like graceful shutdown, backpressure handling, and cancellation safety

Section Mapping

The structure directly mirrors the Tokio tutorial chapters:

Tutorial Section This Repository Focus
Setup / Hello Tokio Part 1: Basic Operations Runtime creation, configuration, threading models
Spawning Part 2: Spawning Task management, cancellation, Send bounds
Shared State Part 3: Shared State Arc, Mutex, RwLock, Semaphore, Barrier, Notify, Watch channels
Channels Part 4: Channels MPSC, Oneshot, Broadcast, backpressure, closure handling
I/O Part 5: I/O File operations, TCP client/server, stream splitting, timeouts
Framing Part 6: Framing Codecs, custom encoders/decoders, length-delimited protocols
Async in Depth Part 7: Async in Depth Future trait, pinning, executors, trait objects
Select Part 8: Select tokio::select! patterns, biased selection, cancellation safety
Streams Part 9: Streams Stream combinators, custom streams, concurrent processing

Recommended approach: Use the Tokio tutorial to learn core concepts, then refer to this repository for additional patterns, detailed explanations, and practical examples for each topic.

Table of Contents

Part 1: $\color{yellow}{\textsf{Basic Operations}}$

Instead of using the #[tokio::main] macro, manually create a Tokio runtime

Configure the runtime to use 2 worker threads

This code demonstrates how to create a single-threaded Tokio runtime using new_current_thread() instead of a multi-threaded runtime.

Part 2: $\color{yellow}{\textsf{Spawning}}$

Section 1: Async Function

This Rust code demonstrates basic asynchronous task spawning using the Tokio runtime.

This code demonstrates safe shared ownership of data across multiple asynchronous tasks using Arc

This code demonstrates how to stop a running asynchronous task before it completes naturally.

This code demonstrates Rust's Send trait enforcement for data shared across asynchronous tasks.

Part 3: $\color{yellow}{\textsf{Shared State}}$

This code demonstrates reference-counted thread-safe sharing of immutable data using Arc

This code demonstrates safe concurrent access to shared mutable state using Arc and Mutex

This code demonstrates how RwLock (Read-Write Lock) enables multiple concurrent readers while maintaining exclusive access for writers.

A semaphore is a synchronization primitive that limits the number of tasks that can access a resource simultaneously.

A deadlock occurs when two or more tasks are waiting for each other to release resources, creating a circular dependency where none can proceed.

A Barrier is a synchronization point where tasks must wait until a specified number of tasks reach that point, then all proceed together.

Notify is a simple, lightweight synchronization primitive for signaling between tasks. One task waits for a signal, another task sends it.

This code demonstrates how a watch channel broadcasts state changes to multiple receivers, where each receiver can observe the latest value.

Part 4: $\color{yellow}{\textsf{Channels}}$

This document demonstrates asynchronous communication between tasks using Tokio's multi-producer, single-consumer (mpsc) channel.

This code demonstrates Tokio's multi-producer, single-consumer (mpsc) channel pattern, where multiple concurrent tasks send messages to a single receiver.

This code demonstrates how Tokio's mpsc (multi-producer, single-consumer) channel handles backpressure using a bounded buffer.

A oneshot channel is a specialized communication primitive in Tokio designed for single-use, one-time message passing between asynchronous tasks.

This code demonstrates how to use Tokio's broadcast channel to send messages from one sender to multiple receivers concurrently.

When working with Tokio's mpsc channels, understanding how channel closure works is crucial for building reliable concurrent applications

Tokio's mpsc channels provide two main methods for sending messages: send() and try_send().

The request-response pattern is a common communication pattern where a client sends a request to a worker and waits for a response.

The tokio::select! macro allows you to wait on multiple async operations simultaneously and proceed with whichever completes first.

Part 5: $\color{yellow}{\textsf{I/O}}$

This code explains how to write files asynchronously with Tokio.

This code explains how to read files asynchronously with Tokio.

This code explains how to read copy asynchronously with Tokio.

This code explains how to use Tokio's BufReader to read files asynchronously.

This code implements a simple asynchronous TCP echo server using Rust and the Tokio runtime.

This code creates a TCP (Transmission Control Protocol) client that connects to a server, sends data, and receives a response.

This document explains how Tokio allows you to split a TCP stream into separate read and write halves, enabling concurrent read and write operations on the same connection.

This document explains how Tokio allows you to split a TCP stream into separate read and write halves, enabling concurrent read and write operations on the same connection.

This document explains how to add timeouts to asynchronous I/O operations in Rust using tokio::time::timeout.

Part 6: $\color{yellow}{\textsf{Framing}}$

LinesCodec is a decoder/encoder that handles newline-delimited text protocols.

This code demonstrates how to use SinkExt from the futures crate to send framed messages over a TCP stream in Rust.

The LengthDelimitedCodec from the tokio-util crate provides automatic message framing for TCP streams by prefixing each message with its length.

This document explains how to implement a custom decoder using Tokio's Decoder trait for a simple binary protocol.

This code implements a custom encoder for a simple binary protocol using Tokio's Encoder trait.

This code demonstrates how to create a unified codec struct that implements both the Encoder and Decoder traits from Tokio for bidirectional communication over network connections.

This code creates a custom codec that combines JSON serialization with length-delimited framing.

This decoder implements a length-prefixed protocol that gracefully handles partial frames - situations where a complete message hasn't arrived yet over the network.

Part 7: $\color{yellow}{\textsf{Async in Depth}}$

When you declare a function with async fn, Rust automatically transforms it into a function that returns a type implementing Future.

Each async fn creates a unique, anonymous future type. Even though both functions have the same signature, they generate different types:

The Future trait is the foundation of async/await in Rust:

This code demonstrates a fundamental async pattern: returning Pending to defer completion.

This code explains how pinning works in a self-referential struct.

An async block is a way to create a future inline.

tokio::join! is a macro that runs multiple futures concurrently and waits for all of them to complete:

tokio::try_join! is a variant of tokio::join! designed specifically for futures that return Result.

An executor is the runtime system that drives futures to completion.

Part 8: $\color{yellow}{\textsf{Sel{}ect}}$

The select! macro polls multiple async operations concurrently and proceeds with whichever one completes first.

This code demonstrates a common async pattern: attempting to receive a message from a channel with a timeout.

This code demonstrates how to use Rust's pattern matching to handle different types of messages received from a tokio channel.

This code demonstrates a common async pattern: attempting to receive a message from a channel with a timeout.

This code demonstrates how to use biased selection in tokio::select! to prioritize certain branches over others. By default, select!

This code demonstrates how to correctly handle cancellation-unsafe operations when using tokio::select!.

This code demonstrates how to use tokio::select! to concurrently wait on three different types of Tokio channels: MPSC, Oneshot, and Broadcast.

This code demonstrates a graceful shutdown pattern - one of the most important patterns in async Rust programming.

This code demonstrates a resetting timeout pattern - a technique where a timeout is continuously reset each time activity occurs.

Part 9: $\color{yellow}{\textsf{Streams}}$

This code demonstrates how to iterate over an async stream using the while let Some pattern.

This code demonstrates how to convert a synchronous iterator (like a Vec) into an asynchronous Stream using tokio_stream::iter.

This code demonstrates how to use the map combinator to transform values in a stream.

This code demonstrates how to use the filter combinator to selectively keep values in a stream based on a condition.

This code demonstrates how to use the then combinator to perform asynchronous transformations on stream values.

This code demonstrates how to use the then combinator to apply an asynchronous function to each element in a stream.

This code demonstrates how to use the skip and take combinators to select specific elements from a stream.

This code demonstrates how to use the fold combinator to aggregate all values in a stream into a single result.

This code demonstrates how to use buffer_unordered to process stream items concurrently rather than sequentially.

his code demonstrates how to implement a custom stream from scratch by implementing the Stream trait.

This code demonstrates how to create a throttled stream that emits values at a controlled rate.

This code demonstrates how to use the merge combinator to combine two independent streams into a single unified stream.

About

A collection of Tokio (Rust async runtime) use case patterns and example code

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages