Cover....1
Title Page....2
Copyright....3
Dedication....4
Contributors....5
Table of Contents....8
Preface....14
Part 1: Asynchronous Programming Fundamentals....22
Chapter 1: Concurrency and Asynchronous Programming: a Detailed Overview....24
Technical requirements....25
An evolutionary journey of multitasking....25
Non-preemptive multitasking....25
Preemptive multitasking....26
Hyper-threading....26
Multicore processors....27
Do you really write synchronous code?....27
Concurrency versus parallelism....28
The mental model I use....29
Let’s draw some parallels to process economics....30
Concurrency and its relation to I/O....32
What about threads provided by the operating system?....33
Choosing the right reference frame....33
Asynchronous versus concurrent....33
The role of the operating system....34
Concurrency from the operating system’s perspective....34
Teaming up with the operating system....35
Communicating with the operating system....35
The CPU and the operating system....36
Down the rabbit hole....37
How does the CPU prevent us from accessing memory we’re not supposed to access?....38
But can’t we just change the page table in the CPU?....39
Interrupts, firmware, and I/O....40
A simplified overview....40
Interrupts....43
Firmware....43
Summary....44
Chapter 2: Concurrency and Asynchronous Programming: a Detailed OverviewHow Programming Languages Model Asynchronous Program Flow....46
Definitions....47
Threads....48
Threads provided by the operating system....50
Creating new threads takes time....50
Each thread has its own stack....50
Context switching....51
Scheduling....51
The advantage of decoupling asynchronous operations from OS threads....52
Example....52
Fibers and green threads....54
Each stack has a fixed space....55
Context switching....56
Scheduling....56
FFI....57
Callback based approaches....58
Coroutines: promises and futures....59
Coroutines and async/await....60
Summary....62
Chapter 3: Understanding OS-Backed Event Queues, System Calls, and Cross-Platform Abstractions....64
Technical requirements....65
Running the Linux examples....66
Why use an OS-backed event queue?....66
Blocking I/O....67
Non-blocking I/O....67
Event queuing via epoll/kqueue and IOCP....68
Readiness-based event queues....68
Completion-based event queues....69
epoll, kqueue, and IOCP....70
Cross-platform event queues....71
System calls, FFI, and cross-platform abstractions....72
The lowest level of abstraction....72
The next level of abstraction....76
The highest level of abstraction....82
Summary....82
Part 2: Event Queues and Green Threads....84
Chapter 4: Create Your Own Event Queue....86
Technical requirements....86
Design and introduction to epoll....87
Is all I/O blocking?....93
The ffi module....94
Bitflags and bitmasks....97
Level-triggered versus edge-triggered events....99
The Poll module....102
The main program....105
Summary....114
Chapter 5: Creating Our Own Fibers....116
Technical requirements....117
How to use the repository alongside the book....117
Background information....118
Instruction sets, hardware architectures, and ABIs....118
The System V ABI for x86-64....120
A quick introduction to Assembly language....123
An example we can build upon....124
Setting up our project....124
An introduction to Rust inline assembly macro....126
Running our example....128
The stack....130
What does the stack look like?....130
Stack sizes....132
Implementing our own fibers....133
Implementing the runtime....136
Guard, skip, and switch functions....142
Finishing thoughts....146
Summary....147
Part 3: Futures and async/await in Rust....148
Chapter 6: Futures in Rust....150
What is a future?....151
Leaf futures....151
Non-leaf futures....151
A mental model of an async runtime....152
What the Rust language and standard library take care of....154
I/O vs CPU-intensive tasks....155
Summary....156
Chapter 7: Coroutines and async/await....158
Technical requirements....158
Introduction to stackless coroutines....159
An example of hand-written coroutines....160
Futures module....162
HTTP module....163
Do all futures have to be lazy?....167
Creating coroutines....168
async/await....175
coroutine/wait....176
corofy—the coroutine preprocessor....176
b-async-await—an example of a coroutine/wait transformation....177
c-async-await—concurrent futures....181
Final thoughts....186
Summary....187
Chapter 8: Runtimes, Wakers, and the Reactor-Executor Pattern....188
Technical requirements....189
Introduction to runtimes and why we need them....190
Reactors and executors....191
Improving our base example....192
Design....194
Changing the current implementation....198
Creating a proper runtime....205
Step 1 – Improving our runtime design by adding a Reactor and a Waker....208
Creating a Waker....209
Changing the Future definition....212
Step 2 – Implementing a proper Executor....213
Step 3 – Implementing a proper Reactor....220
Experimenting with our new runtime....229
An example using concurrency....229
Running multiple futures concurrently and in parallel....230
Summary....232
Chapter 9: Coroutines, Self-Referential Structs, and Pinning....234
Technical requirements....235
Improving our example 1 – variables....235
Setting up the base example....236
Improving our base example....238
Improving our example 2 – references....243
Improving our example 3 – this is… not… good…....248
Discovering self-referential structs....250
What is a move?....252
Pinning in Rust....254
Pinning in theory....255
Definitions....255
Pinning to the heap....256
Pinning to the stack....258
Pin projections and structural pinning....261
Improving our example 4 – pinning to the rescue....262
future.rs....263
http.rs....263
Main.rs....265
executor.rs....267
Summary....269
Chapter 10: Creating Your Own Runtime....272
Technical requirements....272
Setting up our example....274
main.rs....274
future.rs....275
http.rs....275
executor.rs....277
reactor.rs....280
Experimenting with our runtime....282
Challenges with asynchronous Rust....286
Explicit versus implicit reactor instantiation....286
Ergonomics versus efficiency and flexibility....287
Common traits that everyone agrees about....288
Async drop....289
The future of asynchronous Rust....290
Summary....290
Epilogue....293
Index....296
About PACKT....302
Other Books You May Enjoy....303
Step into the world of asynchronous programming with confidence by conquering the challenges of unclear concepts with this hands-on guide. Using functional examples, this book simplifies the trickiest concepts, exploring goroutines, fibers, futures, and callbacks to help you navigate the vast Rust async ecosystem with ease.
You'll start by building a solid foundation in asynchronous programming and explore diverse strategies for modeling program flow. The book then guides you through concepts like epoll, coroutines, green threads, and callbacks using practical examples. The final section focuses on Rust, examining futures, generators, and the reactor-executor pattern. You'll apply your knowledge to create your own runtime, solidifying expertise in this dynamic domain. Throughout the book, you'll not only gain proficiency in Rust's async features but also see how Rust models asynchronous program flow.
By the end of the book, you'll possess the knowledge and practical skills needed to actively contribute to the Rust async ecosystem.
This book is for programmers who want to enhance their understanding of asynchronous programming, especially those experienced in VM'ed or interpreted languages like C#, Java, Python, JavaScript, and Go. If you work with C or C++ but have had limited exposure to asynchronous programming, this book serves as a resource to broaden your knowledge in this area.
Although the examples are predominantly in Rust, the intricacies of Rust's futures are covered in detail. So, anyone with a keen interest in learning Rust or with working knowledge of Rust will be able to get the most out of this book.