continued version 2
This commit is contained in:
@@ -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("127.0.0.1:3000");
|
||||||
|
</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("127.0.0.1:3000").await.unwrap();// <- yield
|
||||||
|
println!("connected!");
|
||||||
|
let result = stream.write(b"hello world\n").await; // <- yield
|
||||||
|
println!("message sent!");
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</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 -->
|
||||||
|
|||||||
@@ -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 "type erased" 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 "play" 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 "play" 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 "normal" 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 -->
|
||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 "async" 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 -->
|
||||||
|
|||||||
@@ -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 "async" 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 -->
|
||||||
|
|||||||
235
book/print.html
235
book/print.html
@@ -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 "async" 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("127.0.0.1:3000");
|
||||||
|
</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("127.0.0.1:3000").await.unwrap();// <- yield
|
||||||
|
println!("connected!");
|
||||||
|
let result = stream.write(b"hello world\n").await; // <- yield
|
||||||
|
println!("message sent!");
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</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 "type erased" 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 "play" 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 "play" 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 "normal" 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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user