continued version 2

This commit is contained in:
Carl Fredrik Samson
2020-02-24 23:25:48 +01:00
parent 9f2dd2af47
commit 70c4020059
16 changed files with 716 additions and 322 deletions

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html" class="active"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html" class="active"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -163,60 +163,102 @@
information that will help demystify some of the concepts we encounter.</p> information that will help demystify some of the concepts we encounter.</p>
<p>Actually, after going through these concepts, implementing futures will seem <p>Actually, after going through these concepts, implementing futures will seem
pretty simple. I promise.</p> pretty simple. I promise.</p>
<h2><a class="header" href="#async-in-rust" id="async-in-rust">Async in Rust</a></h2> <h2><a class="header" href="#futures" id="futures">Futures</a></h2>
<p>Let's get some of the common roadblocks out of the way first.</p> <p>So what is a future?</p>
<p>Async in Rust is different from most other languages in the sense that Rust <p>A future is a representation of some operation which will complete in the
has a very lightweight runtime.</p> future.</p>
<p>Languages like C#, JavaScript, Java and GO, already includes a runtime <p>Async in Rust uses a <code>Poll</code> based approach, in which an asynchronous task will
for handling concurrency. So if you come from one of those languages this will have three phases.</p>
<ol>
<li><strong>The Poll phase.</strong> A Future is polled which result in the task progressing until
a point where it can no longer make progress. We often refer to the part of the
runtime which polls a Future as an executor.</li>
<li><strong>The Wait phase.</strong> An event source, most often referred to as a reactor,
registers that a Future is waiting for an event to happen and makes sure that it
will wake the Future when that event is ready.</li>
<li><strong>The Wake phase.</strong> The event happens and the Future is woken up. It's now up
to the executor which polled the Future in step 1 to schedule the future to be
polled again and make further progress until it completes or reaches a new point
where it can't make further progress and the cycle repeats.</li>
</ol>
<p>Now, when we talk about futures I find it useful to make a distinction between
<strong>non-leaf</strong> futures and <strong>leaf</strong> futures early on because in practice they're
pretty different from one another.</p>
<h3><a class="header" href="#leaf-futures" id="leaf-futures">Leaf futures</a></h3>
<p>Runtimes create <em>leaf futures</em> which represents a resource like a socket.</p>
<pre><code class="language-rust ignore noplaypen">// stream is a **leaf-future**
let mut stream = tokio::net::TcpStream::connect(&quot;127.0.0.1:3000&quot;);
</code></pre>
<p>Operations on these resources, like a <code>Read</code> on a socket, will be non-blocking
and return a future which we call a leaf future since it's the future which
we're actually waiting on.</p>
<p>It's unlikely that you'll implement a leaf future yourself unless you're writing
a runtime, but we'll go through how they're constructed in this book as well.</p>
<p>It's also unlikely that you'll pass a leaf-future to a runtime and run it to
completion alone as you'll understand by reading the next paragraph.</p>
<h3><a class="header" href="#non-leaf-futures" id="non-leaf-futures">Non-leaf-futures</a></h3>
<p>Non-leaf-futures is the kind of futures we as <em>users</em> of a runtime writes
ourselves using the <code>async</code> keyword to create a <strong>task</strong> which can be run on the
executor.</p>
<p>The bulk of an async program will consist of non-leaf-futures, which are a kind
of pause-able computation. This is an important distinction since these futures represents a <em>set of operations</em>. Often, such a task will <code>await</code> a leaf future
as one of many operations to complete the task.</p>
<pre><code class="language-rust ignore noplaypen">// Non-leaf-future
let non_leaf = async {
let mut stream = TcpStream::connect(&quot;127.0.0.1:3000&quot;).await.unwrap();// &lt;- yield
println!(&quot;connected!&quot;);
let result = stream.write(b&quot;hello world\n&quot;).await; // &lt;- yield
println!(&quot;message sent!&quot;);
...
};
</code></pre>
<p>The key to these tasks is that they're able to yield control to the runtime's
scheduler and then resume execution again where it left off at a later point.</p>
<p>In contrast to leaf futures, these kind of futures does not themselves represent
an I/O resource. When we poll these futures we either run some code or we yield
to the scheduler while waiting for some resource to signal us that it's ready so
we can resume where we left off.</p>
<h2><a class="header" href="#runtimes" id="runtimes">Runtimes</a></h2>
<p>Languages like C#, JavaScript, Java, GO and many others comes with a runtime
for handling concurrency. So if you come from one of those languages this will
seem a bit strange to you.</p> seem a bit strange to you.</p>
<p>In Rust you will have to make an active choice about which runtime to use.</p> <p>Rust is different from these languages in the sense that Rust doesn't come with
a runtime for handling concurrency, so you need to use a library which provide
this for you.</p>
<p>Quite a bit of complexity attributed to <code>Futures</code> are actually complexity rooted
in runtimes. Creating an efficient runtime is hard.</p>
<p>Learning how to use one correctly requires quite a bit of effort as well, but
you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.</p>
<p>The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often, in other languages
you'll just use the one provided for you.</p>
<p>An async runtime can be divided into two parts:</p>
<ol>
<li>The Executor</li>
<li>The Reactor</li>
</ol>
<p>When Rusts Futures were designed there was a desire to separate the job of
notifying a <code>Future</code> that it can do more work, and actually doing the work
on the <code>Future</code>.</p>
<p>You can think of the former as the reactor's job, and the latter as the
executors job. These two parts of a runtime interacts using the <code>Waker</code> type.</p>
<p>The two most popular runtimes for <code>Futures</code> as of writing this is:</p>
<ul>
<li><a href="https://github.com/async-rs/async-std">async-std</a></li>
<li><a href="https://github.com/tokio-rs/tokio">Tokio</a></li>
</ul>
<h3><a class="header" href="#what-rusts-standard-library-takes-care-of" id="what-rusts-standard-library-takes-care-of">What Rust's standard library takes care of</a></h3> <h3><a class="header" href="#what-rusts-standard-library-takes-care-of" id="what-rusts-standard-library-takes-care-of">What Rust's standard library takes care of</a></h3>
<ol> <ol>
<li>The definition of an interruptible task</li> <li>A common interface representing an operation which will be completed in the
<li>An efficient technique to start, suspend, resume and store tasks which are future through the <code>Future</code> trait.</li>
executed concurrently.</li> <li>An ergonomic way of creating tasks which can be suspended and resumed through
<li>A defined way to wake up a suspended task</li> the <code>async</code> and <code>await</code> keywords.</li>
<li>A defined interface wake up a suspended task through the <code>Waker</code> type.</li>
</ol> </ol>
<p>That's really what Rusts standard library does. As you see there is no definition <p>That's really what Rusts standard library does. As you see there is no definition
of non-blocking I/O, how these tasks are created or how they're run.</p> of non-blocking I/O, how these tasks are created or how they're run.</p>
<h3><a class="header" href="#what-you-need-to-find-elsewhere" id="what-you-need-to-find-elsewhere">What you need to find elsewhere</a></h3> <h2><a class="header" href="#bonus-section" id="bonus-section">Bonus section</a></h2>
<p>A runtime. Well, in Rust we normally divide the runtime into two parts:</p>
<ul>
<li>The Reactor</li>
<li>The Executor</li>
</ul>
<p>Reactors create leaf <code>Futures</code>, and provides things like non-blocking sockets,
an event queue and so on.</p>
<p>Executors, accepts one or more asynchronous tasks called <code>Futures</code> and takes
care of actually running the code we write, suspend the tasks when they're
waiting for I/O and resume them.</p>
<p>In theory, we could choose one <code>Reactor</code> and one <code>Executor</code> that have nothing
to do with each other besides that one creates leaf <code>Futures</code> and the other one
runs them, but in reality today you'll most often get both in a <code>Runtime</code>.</p>
<p>There are mainly two such runtimes today <a href="https://github.com/async-rs/async-std">async_std</a> and <a href="https://github.com/tokio-rs/tokio">tokio</a>.</p>
<p>Quite a bit of complexity attributed to <code>Futures</code> are actually complexity rooted
in runtimes. Creating an efficient runtime is hard. </p>
<p>Learning how to use one correctly can require quite a bit of effort as well, but you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.</p>
<p>The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often you'll just use
the one provided for you.</p>
<h2><a class="header" href="#futures-10-and-futures-30" id="futures-10-and-futures-30">Futures 1.0 and Futures 3.0</a></h2>
<p>I'll not spend too much time on this, but it feels wrong to not mention that
there have been several iterations on how async should work in Rust.</p>
<p><code>Futures 3.0</code> works with the relatively new <code>async/await</code> syntax in Rust and
it's what we'll learn.</p>
<p>Now, since this is rather recent, you can encounter creates that use <code>Futures 1.0</code>
still. This will get resolved in time, but unfortunately it's not always easy
to know in advance.</p>
<p>A good sign is that if you're required to use combinators like <code>and_then</code> then
you're using <code>Futures 1.0</code>.</p>
<p>While they're not directly compatible, there is a tool that let's you relatively
easily convert a <code>Future 1.0</code> to a <code>Future 3.0</code> and vice a versa. You can find
all you need in the <a href="https://github.com/rust-lang/futures-rs"><code>futures-rs</code></a> crate and all
<a href="https://rust-lang.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html">information you need here</a>.</p>
<h2><a class="header" href="#first-things-first" id="first-things-first">First things first</a></h2>
<p>If you find the concepts of concurrency and async programming confusing in <p>If you find the concepts of concurrency and async programming confusing in
general, I know where you're coming from and I have written some resources to general, I know where you're coming from and I have written some resources to
try to give a high level overview that will make it easier to learn Rusts try to give a high level overview that will make it easier to learn Rusts
@@ -243,7 +285,7 @@ it needs to be, so go on and read these chapters if you feel a bit unsure. </p>
<a rel="next" href="2_trait_objects.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <a rel="next" href="2_waker_context.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i> <i class="fa fa-angle-right"></i>
</a> </a>
@@ -261,7 +303,7 @@ it needs to be, so go on and read these chapters if you feel a bit unsure. </p>
<a href="2_trait_objects.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <a href="2_waker_context.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i> <i class="fa fa-angle-right"></i>
</a> </a>
@@ -270,6 +312,21 @@ it needs to be, so go on and read these chapters if you feel a bit unsure. </p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -3,7 +3,7 @@
<head> <head>
<!-- Book generated using mdBook --> <!-- Book generated using mdBook -->
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Trait objects and fat pointers - Futures Explained in 200 Lines of Rust</title> <title>Waker and Context - Futures Explained in 200 Lines of Rust</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html" class="active"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html" class="active"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -149,27 +149,48 @@
<div id="content" class="content"> <div id="content" class="content">
<main> <main>
<h1><a class="header" href="#trait-objects-and-fat-pointers" id="trait-objects-and-fat-pointers">Trait objects and fat pointers</a></h1> <h1><a class="header" href="#waker-and-context" id="waker-and-context">Waker and Context</a></h1>
<blockquote> <blockquote>
<p><strong>Relevant for:</strong></p> <p><strong>Relevant for:</strong></p>
<ul> <ul>
<li>Understanding how the Waker object is constructed</li> <li>Understanding how the Waker object is constructed</li>
<li>Getting a basic feel for &quot;type erased&quot; objects and what they are</li> <li>Learning how the runtime know when a leaf-future can resume</li>
<li>Learning the basics of dynamic dispatch</li> <li>Learning the basics of dynamic dispatch and trait objects</li>
</ul> </ul>
<p>The <code>Waker</code> type is described as part of <a href="https://github.com/rust-lang/rfcs/blob/master/text/2592-futures.md#waking-up">RFC#2592</a>.</p>
</blockquote> </blockquote>
<h2><a class="header" href="#trait-objects-and-dynamic-dispatch" id="trait-objects-and-dynamic-dispatch">Trait objects and dynamic dispatch</a></h2> <h2><a class="header" href="#the-waker" id="the-waker">The Waker</a></h2>
<p>One of the most confusing things we encounter when implementing our own <code>Futures</code> <p>The <code>Waker</code> type allows for a loose coupling between the reactor-part and the executor-part of a runtime.</p>
is how we implement a <code>Waker</code> . Creating a <code>Waker</code> involves creating a <code>vtable</code> <p>By having a wake up mechanism that is <em>not</em> tied to the thing that executes
which allows us to use dynamic dispatch to call methods on a <em>type erased</em> trait the future, runtime-implementors can come up with interesting new wake-up
mechanisms. An example of this can be spawning a thread to do some work that
eventually notifies the future, completely independent of the current runtime.</p>
<p>Without a waker, the executor would be the <em>only</em> way to notify a running
task, whereas with the waker, we get a loose coupling where it's easy to
extend the ecosystem with new leaf-level tasks.</p>
<blockquote>
<p>If you want to read more about the reasoning behind the <code>Waker</code> type I can
recommend <a href="https://boats.gitlab.io/blog/post/wakers-i/">Withoutboats articles series about them</a>.</p>
</blockquote>
<h2><a class="header" href="#the-context-type" id="the-context-type">The Context type</a></h2>
<p>As the docs state as of now this type only wrapps a <code>Waker</code>, but it gives some
flexibility for future evolutions of the API in Rust. The context can hold
task-local storage and provide space for debugging hooks in later iterations.</p>
<h2><a class="header" href="#understanding-the-waker" id="understanding-the-waker">Understanding the <code>Waker</code></a></h2>
<p>One of the most confusing things we encounter when implementing our own <code>Futures</code>
is how we implement a <code>Waker</code> . Creating a <code>Waker</code> involves creating a <code>vtable</code>
which allows us to use dynamic dispatch to call methods on a <em>type erased</em> trait
object we construct our selves.</p> object we construct our selves.</p>
<blockquote> <blockquote>
<p>If you want to know more about dynamic dispatch in Rust I can recommend an article written by Adam Schwalm called <a href="https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/">Exploring Dynamic Dispatch in Rust</a>.</p> <p>If you want to know more about dynamic dispatch in Rust I can recommend an
article written by Adam Schwalm called <a href="https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/">Exploring Dynamic Dispatch in Rust</a>.</p>
</blockquote> </blockquote>
<p>Let's explain this a bit more in detail.</p> <p>Let's explain this a bit more in detail.</p>
<h2><a class="header" href="#fat-pointers-in-rust" id="fat-pointers-in-rust">Fat pointers in Rust</a></h2> <h2><a class="header" href="#fat-pointers-in-rust" id="fat-pointers-in-rust">Fat pointers in Rust</a></h2>
<p>Let's take a look at the size of some different pointer types in Rust. If we <p>To get a better understanding of how we implement the <code>Waker</code> in Rust, we need
run the following code. <em>(You'll have to press &quot;play&quot; to see the output)</em>:</p> to take a step back and talk about some fundamentals. Let's start by taking a
look at the size of some different pointer types in Rust. </p>
<p>Run the following code <em>(You'll have to press &quot;play&quot; to see the output)</em>:</p>
<pre><pre class="playpen"><code class="language-rust"># use std::mem::size_of; <pre><pre class="playpen"><code class="language-rust"># use std::mem::size_of;
trait SomeTrait { } trait SomeTrait { }
@@ -205,7 +226,8 @@ information.</p>
<li>The second 8 bytes points to the <code>vtable</code> for the trait object</li> <li>The second 8 bytes points to the <code>vtable</code> for the trait object</li>
</ul> </ul>
<p>The reason for this is to allow us to refer to an object we know nothing about <p>The reason for this is to allow us to refer to an object we know nothing about
except that it implements the methods defined by our trait. To accomplish this we use <em>dynamic dispatch</em>.</p> except that it implements the methods defined by our trait. To accomplish this
we use <em>dynamic dispatch</em>.</p>
<p>Let's explain this in code instead of words by implementing our own trait <p>Let's explain this in code instead of words by implementing our own trait
object from these parts:</p> object from these parts:</p>
<blockquote> <blockquote>
@@ -273,9 +295,20 @@ fn main() {
} }
</code></pre></pre> </code></pre></pre>
<p>The reason we go through this will be clear later on when we implement our own <p>Now that you know this you also know why how we implement the <code>Waker</code> type
<code>Waker</code> we'll actually set up a <code>vtable</code> like we do here to and knowing what in Rust.</p>
it is will make this much less mysterious.</p> <p>Later on, when we implement our own <code>Waker</code> we'll actually set up a <code>vtable</code>
like we do here to and knowing why we do that and how it works will make this
much less mysterious.</p>
<h2><a class="header" href="#bonus-section" id="bonus-section">Bonus section</a></h2>
<p>You might wonder why the <code>Waker</code> was implemented like this and not just as a
normal trait?</p>
<p>The reason is flexibility. Implementing the Waker the way we do here gives a lot
of flexibility of choosing what memory management scheme to use.</p>
<p>The &quot;normal&quot; way is by using an <code>Arc</code> to use reference count keep track of when
a Waker object can be dropped. However, this is not the only way, you could also
use purely global functions and state, or any other way you wish.</p>
<p>This leaves a lot of options on the table for runtime implementors.</p>
</main> </main>
@@ -315,6 +348,21 @@ it is will make this much less mysterious.</p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html" class="active"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html" class="active"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -666,7 +666,7 @@ pub fn main() {
<nav class="nav-wrapper" aria-label="Page navigation"> <nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons --> <!-- Mobile navigation buttons -->
<a rel="prev" href="2_trait_objects.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <a rel="prev" href="2_waker_context.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i> <i class="fa fa-angle-left"></i>
</a> </a>
@@ -684,7 +684,7 @@ pub fn main() {
<nav class="nav-wide-wrapper" aria-label="Page navigation"> <nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="2_trait_objects.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <a href="2_waker_context.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i> <i class="fa fa-angle-left"></i>
</a> </a>
@@ -699,6 +699,21 @@ pub fn main() {
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html" class="active"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html" class="active"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -470,6 +470,21 @@ we're soon finished.</p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html" class="active"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html" class="active"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -1043,6 +1043,21 @@ exploration will get a lot easier. </p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html" class="active"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html" class="active"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -392,6 +392,21 @@ impl Drop for Reactor {
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html" class="active">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html" class="active">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -254,6 +254,21 @@ articles I've already linked to in the book, here are some of my suggestions:</p
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -1,64 +1,68 @@
/* /* Base16 Atelier Dune Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name> /* Atelier-Dune Comment */
.hljs-comment {
color: rgb(255, 115, 0);;
font-style: italic;
}
.hljs-quote {
color: #AAA;
}
/* Atelier-Dune Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d73737;
}
/* Atelier-Dune Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b65611;
}
/* Atelier-Dune Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #60ac39;
}
/* Atelier-Dune Blue */
.hljs-title,
.hljs-section {
color: #6684e1;
}
/* Atelier-Dune Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #b854d4;
}
*/
.hljs { .hljs {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
background: #f1f1f1;
color: #6e6b5e;
padding: 0.5em; padding: 0.5em;
background: rgba(253, 153, 3, 0.027);
color: black;
} }
.hljs-comment,
.hljs-quote,
.hljs-variable {
color: #008000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-built_in,
.hljs-name,
.hljs-tag {
color: #00f;
}
.hljs-string,
.hljs-title,
.hljs-section,
.hljs-attribute,
.hljs-literal,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-addition {
color: #a31515;
}
.hljs-deletion,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-meta {
color: #2b91af;
}
.hljs-doctag {
color: #808080;
}
.hljs-attr {
color: #f00;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link {
color: #00b0e8;
}
.hljs-emphasis { .hljs-emphasis {
font-style: italic; font-style: italic;
} }
@@ -66,3 +70,13 @@ Visual Studio-like style based on original C# coloring by Jason Diamond <jason@d
.hljs-strong { .hljs-strong {
font-weight: bold; font-weight: bold;
} }
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -151,13 +151,18 @@
<main> <main>
<h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1> <h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1>
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p> <p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p>
<p>The goal is to get a better understanding of <code>Futures</code> by implementing a toy <p>The goal is to get a better understanding of &quot;async&quot; in Rust by creating a toy
<code>Reactor</code>, a very simple <code>Executor</code> and our own <code>Futures</code>. </p> runtime consisting of a <code>Reactor</code> and an <code>Executor</code>, and our own futures which
<p>We'll start off a bit differently than most other explanations. Instead of we can run concurrently.</p>
deferring some of the details about what's special about futures in Rust we <p>We'll start off a bit differently than most other explanations. Instead of
try to tackle that head on first. We'll be as brief as possible, but as thorough deferring some of the details about what <code>Futures</code> are and how they're
as needed. This way, most questions will be answered and explored up front. </p> implemented, we tackle that head on first.</p>
<p>We'll end up with futures that can run an any executor like <code>tokio</code> and <code>async_str</code>.</p> <p>I learn best when I can take basic understandable concepts and build piece by
piece of these basic building blocks until everything is understood. This way,
most questions will be answered and explored up front and the conclusions later
on seems natural.</p>
<p>I've limited myself to a 200 line main example so that we need keep
this fairly brief.</p>
<p>In the end I've made some reader exercises you can do if you want to fix some <p>In the end I've made some reader exercises you can do if you want to fix some
of the most glaring omissions and shortcuts we took and create a slightly better of the most glaring omissions and shortcuts we took and create a slightly better
example yourself.</p> example yourself.</p>
@@ -207,6 +212,21 @@ very well written and very helpful. So thanks!</p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -78,7 +78,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html" class="active">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html" class="active">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -151,13 +151,18 @@
<main> <main>
<h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1> <h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1>
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p> <p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p>
<p>The goal is to get a better understanding of <code>Futures</code> by implementing a toy <p>The goal is to get a better understanding of &quot;async&quot; in Rust by creating a toy
<code>Reactor</code>, a very simple <code>Executor</code> and our own <code>Futures</code>. </p> runtime consisting of a <code>Reactor</code> and an <code>Executor</code>, and our own futures which
<p>We'll start off a bit differently than most other explanations. Instead of we can run concurrently.</p>
deferring some of the details about what's special about futures in Rust we <p>We'll start off a bit differently than most other explanations. Instead of
try to tackle that head on first. We'll be as brief as possible, but as thorough deferring some of the details about what <code>Futures</code> are and how they're
as needed. This way, most questions will be answered and explored up front. </p> implemented, we tackle that head on first.</p>
<p>We'll end up with futures that can run an any executor like <code>tokio</code> and <code>async_str</code>.</p> <p>I learn best when I can take basic understandable concepts and build piece by
piece of these basic building blocks until everything is understood. This way,
most questions will be answered and explored up front and the conclusions later
on seems natural.</p>
<p>I've limited myself to a 200 line main example so that we need keep
this fairly brief.</p>
<p>In the end I've made some reader exercises you can do if you want to fix some <p>In the end I've made some reader exercises you can do if you want to fix some
of the most glaring omissions and shortcuts we took and create a slightly better of the most glaring omissions and shortcuts we took and create a slightly better
example yourself.</p> example yourself.</p>
@@ -215,6 +220,21 @@ very well written and very helpful. So thanks!</p>
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

View File

@@ -80,7 +80,7 @@
<nav id="sidebar" class="sidebar" aria-label="Table of contents"> <nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox"> <div class="sidebar-scrollbox">
<ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_trait_objects.html"><strong aria-hidden="true">2.</strong> Trait objects and fat pointers</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol> <ol class="chapter"><li class="affix"><a href="introduction.html">Introduction</a></li><li><a href="1_background_information.html"><strong aria-hidden="true">1.</strong> Some background information</a></li><li><a href="2_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div> </div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div> <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav> </nav>
@@ -153,13 +153,18 @@
<main> <main>
<h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1> <h1><a class="header" href="#futures-explained-in-200-lines-of-rust" id="futures-explained-in-200-lines-of-rust">Futures Explained in 200 Lines of Rust</a></h1>
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p> <p>This book aims to explain <code>Futures</code> in Rust using an example driven approach.</p>
<p>The goal is to get a better understanding of <code>Futures</code> by implementing a toy <p>The goal is to get a better understanding of &quot;async&quot; in Rust by creating a toy
<code>Reactor</code>, a very simple <code>Executor</code> and our own <code>Futures</code>. </p> runtime consisting of a <code>Reactor</code> and an <code>Executor</code>, and our own futures which
<p>We'll start off a bit differently than most other explanations. Instead of we can run concurrently.</p>
deferring some of the details about what's special about futures in Rust we <p>We'll start off a bit differently than most other explanations. Instead of
try to tackle that head on first. We'll be as brief as possible, but as thorough deferring some of the details about what <code>Futures</code> are and how they're
as needed. This way, most questions will be answered and explored up front. </p> implemented, we tackle that head on first.</p>
<p>We'll end up with futures that can run an any executor like <code>tokio</code> and <code>async_str</code>.</p> <p>I learn best when I can take basic understandable concepts and build piece by
piece of these basic building blocks until everything is understood. This way,
most questions will be answered and explored up front and the conclusions later
on seems natural.</p>
<p>I've limited myself to a 200 line main example so that we need keep
this fairly brief.</p>
<p>In the end I've made some reader exercises you can do if you want to fix some <p>In the end I've made some reader exercises you can do if you want to fix some
of the most glaring omissions and shortcuts we took and create a slightly better of the most glaring omissions and shortcuts we took and create a slightly better
example yourself.</p> example yourself.</p>
@@ -200,60 +205,102 @@ very well written and very helpful. So thanks!</p>
information that will help demystify some of the concepts we encounter.</p> information that will help demystify some of the concepts we encounter.</p>
<p>Actually, after going through these concepts, implementing futures will seem <p>Actually, after going through these concepts, implementing futures will seem
pretty simple. I promise.</p> pretty simple. I promise.</p>
<h2><a class="header" href="#async-in-rust" id="async-in-rust">Async in Rust</a></h2> <h2><a class="header" href="#futures" id="futures">Futures</a></h2>
<p>Let's get some of the common roadblocks out of the way first.</p> <p>So what is a future?</p>
<p>Async in Rust is different from most other languages in the sense that Rust <p>A future is a representation of some operation which will complete in the
has a very lightweight runtime.</p> future.</p>
<p>Languages like C#, JavaScript, Java and GO, already includes a runtime <p>Async in Rust uses a <code>Poll</code> based approach, in which an asynchronous task will
for handling concurrency. So if you come from one of those languages this will have three phases.</p>
<ol>
<li><strong>The Poll phase.</strong> A Future is polled which result in the task progressing until
a point where it can no longer make progress. We often refer to the part of the
runtime which polls a Future as an executor.</li>
<li><strong>The Wait phase.</strong> An event source, most often referred to as a reactor,
registers that a Future is waiting for an event to happen and makes sure that it
will wake the Future when that event is ready.</li>
<li><strong>The Wake phase.</strong> The event happens and the Future is woken up. It's now up
to the executor which polled the Future in step 1 to schedule the future to be
polled again and make further progress until it completes or reaches a new point
where it can't make further progress and the cycle repeats.</li>
</ol>
<p>Now, when we talk about futures I find it useful to make a distinction between
<strong>non-leaf</strong> futures and <strong>leaf</strong> futures early on because in practice they're
pretty different from one another.</p>
<h3><a class="header" href="#leaf-futures" id="leaf-futures">Leaf futures</a></h3>
<p>Runtimes create <em>leaf futures</em> which represents a resource like a socket.</p>
<pre><code class="language-rust ignore noplaypen">// stream is a **leaf-future**
let mut stream = tokio::net::TcpStream::connect(&quot;127.0.0.1:3000&quot;);
</code></pre>
<p>Operations on these resources, like a <code>Read</code> on a socket, will be non-blocking
and return a future which we call a leaf future since it's the future which
we're actually waiting on.</p>
<p>It's unlikely that you'll implement a leaf future yourself unless you're writing
a runtime, but we'll go through how they're constructed in this book as well.</p>
<p>It's also unlikely that you'll pass a leaf-future to a runtime and run it to
completion alone as you'll understand by reading the next paragraph.</p>
<h3><a class="header" href="#non-leaf-futures" id="non-leaf-futures">Non-leaf-futures</a></h3>
<p>Non-leaf-futures is the kind of futures we as <em>users</em> of a runtime writes
ourselves using the <code>async</code> keyword to create a <strong>task</strong> which can be run on the
executor.</p>
<p>The bulk of an async program will consist of non-leaf-futures, which are a kind
of pause-able computation. This is an important distinction since these futures represents a <em>set of operations</em>. Often, such a task will <code>await</code> a leaf future
as one of many operations to complete the task.</p>
<pre><code class="language-rust ignore noplaypen">// Non-leaf-future
let non_leaf = async {
let mut stream = TcpStream::connect(&quot;127.0.0.1:3000&quot;).await.unwrap();// &lt;- yield
println!(&quot;connected!&quot;);
let result = stream.write(b&quot;hello world\n&quot;).await; // &lt;- yield
println!(&quot;message sent!&quot;);
...
};
</code></pre>
<p>The key to these tasks is that they're able to yield control to the runtime's
scheduler and then resume execution again where it left off at a later point.</p>
<p>In contrast to leaf futures, these kind of futures does not themselves represent
an I/O resource. When we poll these futures we either run some code or we yield
to the scheduler while waiting for some resource to signal us that it's ready so
we can resume where we left off.</p>
<h2><a class="header" href="#runtimes" id="runtimes">Runtimes</a></h2>
<p>Languages like C#, JavaScript, Java, GO and many others comes with a runtime
for handling concurrency. So if you come from one of those languages this will
seem a bit strange to you.</p> seem a bit strange to you.</p>
<p>In Rust you will have to make an active choice about which runtime to use.</p> <p>Rust is different from these languages in the sense that Rust doesn't come with
a runtime for handling concurrency, so you need to use a library which provide
this for you.</p>
<p>Quite a bit of complexity attributed to <code>Futures</code> are actually complexity rooted
in runtimes. Creating an efficient runtime is hard.</p>
<p>Learning how to use one correctly requires quite a bit of effort as well, but
you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.</p>
<p>The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often, in other languages
you'll just use the one provided for you.</p>
<p>An async runtime can be divided into two parts:</p>
<ol>
<li>The Executor</li>
<li>The Reactor</li>
</ol>
<p>When Rusts Futures were designed there was a desire to separate the job of
notifying a <code>Future</code> that it can do more work, and actually doing the work
on the <code>Future</code>.</p>
<p>You can think of the former as the reactor's job, and the latter as the
executors job. These two parts of a runtime interacts using the <code>Waker</code> type.</p>
<p>The two most popular runtimes for <code>Futures</code> as of writing this is:</p>
<ul>
<li><a href="https://github.com/async-rs/async-std">async-std</a></li>
<li><a href="https://github.com/tokio-rs/tokio">Tokio</a></li>
</ul>
<h3><a class="header" href="#what-rusts-standard-library-takes-care-of" id="what-rusts-standard-library-takes-care-of">What Rust's standard library takes care of</a></h3> <h3><a class="header" href="#what-rusts-standard-library-takes-care-of" id="what-rusts-standard-library-takes-care-of">What Rust's standard library takes care of</a></h3>
<ol> <ol>
<li>The definition of an interruptible task</li> <li>A common interface representing an operation which will be completed in the
<li>An efficient technique to start, suspend, resume and store tasks which are future through the <code>Future</code> trait.</li>
executed concurrently.</li> <li>An ergonomic way of creating tasks which can be suspended and resumed through
<li>A defined way to wake up a suspended task</li> the <code>async</code> and <code>await</code> keywords.</li>
<li>A defined interface wake up a suspended task through the <code>Waker</code> type.</li>
</ol> </ol>
<p>That's really what Rusts standard library does. As you see there is no definition <p>That's really what Rusts standard library does. As you see there is no definition
of non-blocking I/O, how these tasks are created or how they're run.</p> of non-blocking I/O, how these tasks are created or how they're run.</p>
<h3><a class="header" href="#what-you-need-to-find-elsewhere" id="what-you-need-to-find-elsewhere">What you need to find elsewhere</a></h3> <h2><a class="header" href="#bonus-section" id="bonus-section">Bonus section</a></h2>
<p>A runtime. Well, in Rust we normally divide the runtime into two parts:</p>
<ul>
<li>The Reactor</li>
<li>The Executor</li>
</ul>
<p>Reactors create leaf <code>Futures</code>, and provides things like non-blocking sockets,
an event queue and so on.</p>
<p>Executors, accepts one or more asynchronous tasks called <code>Futures</code> and takes
care of actually running the code we write, suspend the tasks when they're
waiting for I/O and resume them.</p>
<p>In theory, we could choose one <code>Reactor</code> and one <code>Executor</code> that have nothing
to do with each other besides that one creates leaf <code>Futures</code> and the other one
runs them, but in reality today you'll most often get both in a <code>Runtime</code>.</p>
<p>There are mainly two such runtimes today <a href="https://github.com/async-rs/async-std">async_std</a> and <a href="https://github.com/tokio-rs/tokio">tokio</a>.</p>
<p>Quite a bit of complexity attributed to <code>Futures</code> are actually complexity rooted
in runtimes. Creating an efficient runtime is hard. </p>
<p>Learning how to use one correctly can require quite a bit of effort as well, but you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.</p>
<p>The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often you'll just use
the one provided for you.</p>
<h2><a class="header" href="#futures-10-and-futures-30" id="futures-10-and-futures-30">Futures 1.0 and Futures 3.0</a></h2>
<p>I'll not spend too much time on this, but it feels wrong to not mention that
there have been several iterations on how async should work in Rust.</p>
<p><code>Futures 3.0</code> works with the relatively new <code>async/await</code> syntax in Rust and
it's what we'll learn.</p>
<p>Now, since this is rather recent, you can encounter creates that use <code>Futures 1.0</code>
still. This will get resolved in time, but unfortunately it's not always easy
to know in advance.</p>
<p>A good sign is that if you're required to use combinators like <code>and_then</code> then
you're using <code>Futures 1.0</code>.</p>
<p>While they're not directly compatible, there is a tool that let's you relatively
easily convert a <code>Future 1.0</code> to a <code>Future 3.0</code> and vice a versa. You can find
all you need in the <a href="https://github.com/rust-lang/futures-rs"><code>futures-rs</code></a> crate and all
<a href="https://rust-lang.github.io/futures-rs/blog/2019/04/18/compatibility-layer.html">information you need here</a>.</p>
<h2><a class="header" href="#first-things-first" id="first-things-first">First things first</a></h2>
<p>If you find the concepts of concurrency and async programming confusing in <p>If you find the concepts of concurrency and async programming confusing in
general, I know where you're coming from and I have written some resources to general, I know where you're coming from and I have written some resources to
try to give a high level overview that will make it easier to learn Rusts try to give a high level overview that will make it easier to learn Rusts
@@ -268,27 +315,48 @@ try to give a high level overview that will make it easier to learn Rusts
it needs to be, so go on and read these chapters if you feel a bit unsure. </p> it needs to be, so go on and read these chapters if you feel a bit unsure. </p>
<p>I'll be right here when you're back.</p> <p>I'll be right here when you're back.</p>
<p>However, if you feel that you have the basics covered, then let's get moving!</p> <p>However, if you feel that you have the basics covered, then let's get moving!</p>
<h1><a class="header" href="#trait-objects-and-fat-pointers" id="trait-objects-and-fat-pointers">Trait objects and fat pointers</a></h1> <h1><a class="header" href="#waker-and-context" id="waker-and-context">Waker and Context</a></h1>
<blockquote> <blockquote>
<p><strong>Relevant for:</strong></p> <p><strong>Relevant for:</strong></p>
<ul> <ul>
<li>Understanding how the Waker object is constructed</li> <li>Understanding how the Waker object is constructed</li>
<li>Getting a basic feel for &quot;type erased&quot; objects and what they are</li> <li>Learning how the runtime know when a leaf-future can resume</li>
<li>Learning the basics of dynamic dispatch</li> <li>Learning the basics of dynamic dispatch and trait objects</li>
</ul> </ul>
<p>The <code>Waker</code> type is described as part of <a href="https://github.com/rust-lang/rfcs/blob/master/text/2592-futures.md#waking-up">RFC#2592</a>.</p>
</blockquote> </blockquote>
<h2><a class="header" href="#trait-objects-and-dynamic-dispatch" id="trait-objects-and-dynamic-dispatch">Trait objects and dynamic dispatch</a></h2> <h2><a class="header" href="#the-waker" id="the-waker">The Waker</a></h2>
<p>One of the most confusing things we encounter when implementing our own <code>Futures</code> <p>The <code>Waker</code> type allows for a loose coupling between the reactor-part and the executor-part of a runtime.</p>
is how we implement a <code>Waker</code> . Creating a <code>Waker</code> involves creating a <code>vtable</code> <p>By having a wake up mechanism that is <em>not</em> tied to the thing that executes
which allows us to use dynamic dispatch to call methods on a <em>type erased</em> trait the future, runtime-implementors can come up with interesting new wake-up
mechanisms. An example of this can be spawning a thread to do some work that
eventually notifies the future, completely independent of the current runtime.</p>
<p>Without a waker, the executor would be the <em>only</em> way to notify a running
task, whereas with the waker, we get a loose coupling where it's easy to
extend the ecosystem with new leaf-level tasks.</p>
<blockquote>
<p>If you want to read more about the reasoning behind the <code>Waker</code> type I can
recommend <a href="https://boats.gitlab.io/blog/post/wakers-i/">Withoutboats articles series about them</a>.</p>
</blockquote>
<h2><a class="header" href="#the-context-type" id="the-context-type">The Context type</a></h2>
<p>As the docs state as of now this type only wrapps a <code>Waker</code>, but it gives some
flexibility for future evolutions of the API in Rust. The context can hold
task-local storage and provide space for debugging hooks in later iterations.</p>
<h2><a class="header" href="#understanding-the-waker" id="understanding-the-waker">Understanding the <code>Waker</code></a></h2>
<p>One of the most confusing things we encounter when implementing our own <code>Futures</code>
is how we implement a <code>Waker</code> . Creating a <code>Waker</code> involves creating a <code>vtable</code>
which allows us to use dynamic dispatch to call methods on a <em>type erased</em> trait
object we construct our selves.</p> object we construct our selves.</p>
<blockquote> <blockquote>
<p>If you want to know more about dynamic dispatch in Rust I can recommend an article written by Adam Schwalm called <a href="https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/">Exploring Dynamic Dispatch in Rust</a>.</p> <p>If you want to know more about dynamic dispatch in Rust I can recommend an
article written by Adam Schwalm called <a href="https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/">Exploring Dynamic Dispatch in Rust</a>.</p>
</blockquote> </blockquote>
<p>Let's explain this a bit more in detail.</p> <p>Let's explain this a bit more in detail.</p>
<h2><a class="header" href="#fat-pointers-in-rust" id="fat-pointers-in-rust">Fat pointers in Rust</a></h2> <h2><a class="header" href="#fat-pointers-in-rust" id="fat-pointers-in-rust">Fat pointers in Rust</a></h2>
<p>Let's take a look at the size of some different pointer types in Rust. If we <p>To get a better understanding of how we implement the <code>Waker</code> in Rust, we need
run the following code. <em>(You'll have to press &quot;play&quot; to see the output)</em>:</p> to take a step back and talk about some fundamentals. Let's start by taking a
look at the size of some different pointer types in Rust. </p>
<p>Run the following code <em>(You'll have to press &quot;play&quot; to see the output)</em>:</p>
<pre><pre class="playpen"><code class="language-rust"># use std::mem::size_of; <pre><pre class="playpen"><code class="language-rust"># use std::mem::size_of;
trait SomeTrait { } trait SomeTrait { }
@@ -324,7 +392,8 @@ information.</p>
<li>The second 8 bytes points to the <code>vtable</code> for the trait object</li> <li>The second 8 bytes points to the <code>vtable</code> for the trait object</li>
</ul> </ul>
<p>The reason for this is to allow us to refer to an object we know nothing about <p>The reason for this is to allow us to refer to an object we know nothing about
except that it implements the methods defined by our trait. To accomplish this we use <em>dynamic dispatch</em>.</p> except that it implements the methods defined by our trait. To accomplish this
we use <em>dynamic dispatch</em>.</p>
<p>Let's explain this in code instead of words by implementing our own trait <p>Let's explain this in code instead of words by implementing our own trait
object from these parts:</p> object from these parts:</p>
<blockquote> <blockquote>
@@ -392,9 +461,20 @@ fn main() {
} }
</code></pre></pre> </code></pre></pre>
<p>The reason we go through this will be clear later on when we implement our own <p>Now that you know this you also know why how we implement the <code>Waker</code> type
<code>Waker</code> we'll actually set up a <code>vtable</code> like we do here to and knowing what in Rust.</p>
it is will make this much less mysterious.</p> <p>Later on, when we implement our own <code>Waker</code> we'll actually set up a <code>vtable</code>
like we do here to and knowing why we do that and how it works will make this
much less mysterious.</p>
<h2><a class="header" href="#bonus-section-1" id="bonus-section-1">Bonus section</a></h2>
<p>You might wonder why the <code>Waker</code> was implemented like this and not just as a
normal trait?</p>
<p>The reason is flexibility. Implementing the Waker the way we do here gives a lot
of flexibility of choosing what memory management scheme to use.</p>
<p>The &quot;normal&quot; way is by using an <code>Arc</code> to use reference count keep track of when
a Waker object can be dropped. However, this is not the only way, you could also
use purely global functions and state, or any other way you wish.</p>
<p>This leaves a lot of options on the table for runtime implementors.</p>
<h1><a class="header" href="#generators" id="generators">Generators</a></h1> <h1><a class="header" href="#generators" id="generators">Generators</a></h1>
<blockquote> <blockquote>
<p><strong>Relevant for:</strong></p> <p><strong>Relevant for:</strong></p>
@@ -2344,6 +2424,21 @@ articles I've already linked to in the book, here are some of my suggestions:</p
</div> </div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag --> <!-- Google Analytics Tag -->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -20,6 +20,20 @@ So what is a future?
A future is a representation of some operation which will complete in the A future is a representation of some operation which will complete in the
future. future.
Async in Rust uses a `Poll` based approach, in which an asynchronous task will
have three phases.
1. **The Poll phase.** A Future is polled which result in the task progressing until
a point where it can no longer make progress. We often refer to the part of the
runtime which polls a Future as an executor.
2. **The Wait phase.** An event source, most often referred to as a reactor,
registers that a Future is waiting for an event to happen and makes sure that it
will wake the Future when that event is ready.
3. **The Wake phase.** The event happens and the Future is woken up. It's now up
to the executor which polled the Future in step 1 to schedule the future to be
polled again and make further progress until it completes or reaches a new point
where it can't make further progress and the cycle repeats.
Now, when we talk about futures I find it useful to make a distinction between Now, when we talk about futures I find it useful to make a distinction between
**non-leaf** futures and **leaf** futures early on because in practice they're **non-leaf** futures and **leaf** futures early on because in practice they're
pretty different from one another. pretty different from one another.
@@ -49,18 +63,18 @@ Non-leaf-futures is the kind of futures we as _users_ of a runtime writes
ourselves using the `async` keyword to create a **task** which can be run on the ourselves using the `async` keyword to create a **task** which can be run on the
executor. executor.
This is an important distinction since these futures represents a The bulk of an async program will consist of non-leaf-futures, which are a kind
_set of operations_. Often, such a task will `await` a leaf future as one of of pause-able computation. This is an important distinction since these futures represents a _set of operations_. Often, such a task will `await` a leaf future
many operations to complete the task. as one of many operations to complete the task.
```rust ```rust, ignore, noplaypen
// Non-leaf-future // Non-leaf-future
let non_leaf = async { let non_leaf = async {
let mut stream = TcpStream::connect("127.0.0.1:3000").await.unwrap();// <- yield let mut stream = TcpStream::connect("127.0.0.1:3000").await.unwrap();// <- yield
println!("connected!"); println!("connected!");
let result = stream.write(b"hello world\n").await; // <- yield let result = stream.write(b"hello world\n").await; // <- yield
println!("message sent!"); println!("message sent!");
// ... ...
}; };
``` ```
@@ -72,22 +86,7 @@ an I/O resource. When we poll these futures we either run some code or we yield
to the scheduler while waiting for some resource to signal us that it's ready so to the scheduler while waiting for some resource to signal us that it's ready so
we can resume where we left off. we can resume where we left off.
### Runtimes ## Runtimes
Quite a bit of complexity attributed to `Futures` are actually complexity rooted
in runtimes. Creating an efficient runtime is hard.
Learning how to use one correctly can require quite a bit of effort as well, but
you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.
The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often you'll just use
the one provided for you.
## Async in Rust
Let's get some of the common roadblocks out of the way first.
Languages like C#, JavaScript, Java, GO and many others comes with a runtime Languages like C#, JavaScript, Java, GO and many others comes with a runtime
for handling concurrency. So if you come from one of those languages this will for handling concurrency. So if you come from one of those languages this will
@@ -97,9 +96,33 @@ Rust is different from these languages in the sense that Rust doesn't come with
a runtime for handling concurrency, so you need to use a library which provide a runtime for handling concurrency, so you need to use a library which provide
this for you. this for you.
In other words you'll have to make an active choice about which runtime to use Quite a bit of complexity attributed to `Futures` are actually complexity rooted
which will of course seem foreign if the environment you come from provides one in runtimes. Creating an efficient runtime is hard.
which "everybody" uses.
Learning how to use one correctly requires quite a bit of effort as well, but
you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.
The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often, in other languages
you'll just use the one provided for you.
An async runtime can be divided into two parts:
1. The Executor
2. The Reactor
When Rusts Futures were designed there was a desire to separate the job of
notifying a `Future` that it can do more work, and actually doing the work
on the `Future`.
You can think of the former as the reactor's job, and the latter as the
executors job. These two parts of a runtime interacts using the `Waker` type.
The two most popular runtimes for `Futures` as of writing this is:
- [async-std](https://github.com/async-rs/async-std)
- [Tokio](https://github.com/tokio-rs/tokio)
### What Rust's standard library takes care of ### What Rust's standard library takes care of
@@ -107,29 +130,11 @@ which "everybody" uses.
future through the `Future` trait. future through the `Future` trait.
2. An ergonomic way of creating tasks which can be suspended and resumed through 2. An ergonomic way of creating tasks which can be suspended and resumed through
the `async` and `await` keywords. the `async` and `await` keywords.
3. A defined interface wake up a suspended task through the `Waker` trait. 3. A defined interface wake up a suspended task through the `Waker` type.
That's really what Rusts standard library does. As you see there is no definition That's really what Rusts standard library does. As you see there is no definition
of non-blocking I/O, how these tasks are created or how they're run. of non-blocking I/O, how these tasks are created or how they're run.
### What you need to find elsewhere
A runtime, often just referred to as an `Executor`.
There are mainly two such runtimes in wide use in the community today
[async_std][async_std] and [tokio][tokio].
Executors, accepts one or more asynchronous tasks (`Futures`) and takes
care of actually running the code we write, suspend the tasks when they're
waiting for I/O and resume them when they can make progress.
>Now, you might stumble upon articles/comments which mentions both an `Executor`
and an `Reactor` (also referred to as a `Driver`) as if they're well defined
concepts you need to know about. This is not true. In practice today you'll only
interface with the runtime, which provides leaf futures which actually wait for
some I/O operation, and the executor where
## Bonus section ## Bonus section
If you find the concepts of concurrency and async programming confusing in If you find the concepts of concurrency and async programming confusing in

View File

@@ -5,24 +5,50 @@
> - Understanding how the Waker object is constructed > - Understanding how the Waker object is constructed
> - Learning how the runtime know when a leaf-future can resume > - Learning how the runtime know when a leaf-future can resume
> - Learning the basics of dynamic dispatch and trait objects > - Learning the basics of dynamic dispatch and trait objects
>
> The `Waker` type is described as part of [RFC#2592][rfc2592].
## The Waker ## The Waker
The `Waker` trait is an interface where a The `Waker` type allows for a loose coupling between the reactor-part and the executor-part of a runtime.
One of the most confusing things we encounter when implementing our own `Futures` By having a wake up mechanism that is _not_ tied to the thing that executes
is how we implement a `Waker` . Creating a `Waker` involves creating a `vtable` the future, runtime-implementors can come up with interesting new wake-up
which allows us to use dynamic dispatch to call methods on a _type erased_ trait mechanisms. An example of this can be spawning a thread to do some work that
eventually notifies the future, completely independent of the current runtime.
Without a waker, the executor would be the _only_ way to notify a running
task, whereas with the waker, we get a loose coupling where it's easy to
extend the ecosystem with new leaf-level tasks.
> If you want to read more about the reasoning behind the `Waker` type I can
> recommend [Withoutboats articles series about them](https://boats.gitlab.io/blog/post/wakers-i/).
## The Context type
As the docs state as of now this type only wrapps a `Waker`, but it gives some
flexibility for future evolutions of the API in Rust. The context can hold
task-local storage and provide space for debugging hooks in later iterations.
## Understanding the `Waker`
One of the most confusing things we encounter when implementing our own `Futures`
is how we implement a `Waker` . Creating a `Waker` involves creating a `vtable`
which allows us to use dynamic dispatch to call methods on a _type erased_ trait
object we construct our selves. object we construct our selves.
>If you want to know more about dynamic dispatch in Rust I can recommend an article written by Adam Schwalm called [Exploring Dynamic Dispatch in Rust](https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/). >If you want to know more about dynamic dispatch in Rust I can recommend an
article written by Adam Schwalm called [Exploring Dynamic Dispatch in Rust](https://alschwalm.com/blog/static/2017/03/07/exploring-dynamic-dispatch-in-rust/).
Let's explain this a bit more in detail. Let's explain this a bit more in detail.
## Fat pointers in Rust ## Fat pointers in Rust
Let's take a look at the size of some different pointer types in Rust. If we To get a better understanding of how we implement the `Waker` in Rust, we need
run the following code. _(You'll have to press "play" to see the output)_: to take a step back and talk about some fundamentals. Let's start by taking a
look at the size of some different pointer types in Rust.
Run the following code _(You'll have to press "play" to see the output)_:
``` rust ``` rust
# use std::mem::size_of; # use std::mem::size_of;
@@ -65,7 +91,8 @@ The layout for a pointer to a _trait object_ looks like this:
- The second 8 bytes points to the `vtable` for the trait object - The second 8 bytes points to the `vtable` for the trait object
The reason for this is to allow us to refer to an object we know nothing about The reason for this is to allow us to refer to an object we know nothing about
except that it implements the methods defined by our trait. To accomplish this we use _dynamic dispatch_. except that it implements the methods defined by our trait. To accomplish this
we use _dynamic dispatch_.
Let's explain this in code instead of words by implementing our own trait Let's explain this in code instead of words by implementing our own trait
object from these parts: object from these parts:
@@ -136,6 +163,25 @@ fn main() {
``` ```
The reason we go through this will be clear later on when we implement our own Now that you know this you also know why how we implement the `Waker` type
`Waker` we'll actually set up a `vtable` like we do here to and knowing what in Rust.
it is will make this much less mysterious.
Later on, when we implement our own `Waker` we'll actually set up a `vtable`
like we do here to and knowing why we do that and how it works will make this
much less mysterious.
## Bonus section
You might wonder why the `Waker` was implemented like this and not just as a
normal trait?
The reason is flexibility. Implementing the Waker the way we do here gives a lot
of flexibility of choosing what memory management scheme to use.
The "normal" way is by using an `Arc` to use reference count keep track of when
a Waker object can be dropped. However, this is not the only way, you could also
use purely global functions and state, or any other way you wish.
This leaves a lot of options on the table for runtime implementors.
[rfc2592]:https://github.com/rust-lang/rfcs/blob/master/text/2592-futures.md#waking-up

View File

@@ -1,64 +1,68 @@
/* /* Base16 Atelier Dune Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name> /* Atelier-Dune Comment */
.hljs-comment {
color: rgb(255, 115, 0);;
font-style: italic;
}
.hljs-quote {
color: #AAA;
}
/* Atelier-Dune Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d73737;
}
/* Atelier-Dune Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b65611;
}
/* Atelier-Dune Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #60ac39;
}
/* Atelier-Dune Blue */
.hljs-title,
.hljs-section {
color: #6684e1;
}
/* Atelier-Dune Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #b854d4;
}
*/
.hljs { .hljs {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
background: #f1f1f1;
color: #6e6b5e;
padding: 0.5em; padding: 0.5em;
background: rgba(253, 153, 3, 0.027);
color: black;
} }
.hljs-comment,
.hljs-quote,
.hljs-variable {
color: #008000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-built_in,
.hljs-name,
.hljs-tag {
color: #00f;
}
.hljs-string,
.hljs-title,
.hljs-section,
.hljs-attribute,
.hljs-literal,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-addition {
color: #a31515;
}
.hljs-deletion,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-meta {
color: #2b91af;
}
.hljs-doctag {
color: #808080;
}
.hljs-attr {
color: #f00;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link {
color: #00b0e8;
}
.hljs-emphasis { .hljs-emphasis {
font-style: italic; font-style: italic;
} }
@@ -66,3 +70,13 @@ Visual Studio-like style based on original C# coloring by Jason Diamond <jason@d
.hljs-strong { .hljs-strong {
font-weight: bold; font-weight: bold;
} }
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}