spellcheck intro + 3 first chapters
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 and Pin</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> The 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_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> The 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>
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<!-- Book generated using mdBook -->
|
<!-- Book generated using mdBook -->
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Generators and Pin - Futures Explained in 200 Lines of Rust</title>
|
<title>Generators - 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"><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 and Pin</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> The 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_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> The 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>
|
||||||
@@ -211,7 +211,7 @@ a callback-based approach, where each closure stores all the data it needs
|
|||||||
for computation. This means that as we chain these, the memory required to store
|
for computation. This means that as we chain these, the memory required to store
|
||||||
the needed state increases with each added step.</p>
|
the needed state increases with each added step.</p>
|
||||||
<h3><a class="header" href="#stackless-coroutinesgenerators" id="stackless-coroutinesgenerators">Stackless coroutines/generators</a></h3>
|
<h3><a class="header" href="#stackless-coroutinesgenerators" id="stackless-coroutinesgenerators">Stackless coroutines/generators</a></h3>
|
||||||
<p>This is the model used in Rust today. It a few notable advantages:</p>
|
<p>This is the model used in Rust today. It has a few notable advantages:</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>It's easy to convert normal Rust code to a stackless coroutine using using
|
<li>It's easy to convert normal Rust code to a stackless coroutine using using
|
||||||
async/await as keywords (it can even be done using a macro).</li>
|
async/await as keywords (it can even be done using a macro).</li>
|
||||||
@@ -404,7 +404,7 @@ impl Generator for GeneratorA {
|
|||||||
<p>If you try to compile this you'll get an error (just try it yourself by pressing play).</p>
|
<p>If you try to compile this you'll get an error (just try it yourself by pressing play).</p>
|
||||||
<p>What is the lifetime of <code>&String</code>. It's not the same as the lifetime of <code>Self</code>. It's not <code>static</code>.
|
<p>What is the lifetime of <code>&String</code>. It's not the same as the lifetime of <code>Self</code>. It's not <code>static</code>.
|
||||||
Turns out that it's not possible for us in Rusts syntax to describe this lifetime, which means, that
|
Turns out that it's not possible for us in Rusts syntax to describe this lifetime, which means, that
|
||||||
to make this work, we'll have to let the compiler know that <em>we</em> control this correct.</p>
|
to make this work, we'll have to let the compiler know that <em>we</em> control this correctly ourselves.</p>
|
||||||
<p>That means turning to unsafe.</p>
|
<p>That means turning to unsafe.</p>
|
||||||
<p>Let's try to write an implementation that will compiler using <code>unsafe</code>. As you'll
|
<p>Let's try to write an implementation that will compiler using <code>unsafe</code>. As you'll
|
||||||
see we end up in a <em>self referential struct</em>. A struct which holds references
|
see we end up in a <em>self referential struct</em>. A struct which holds references
|
||||||
@@ -467,7 +467,7 @@ impl Generator for GeneratorA {
|
|||||||
let borrowed = &to_borrow;
|
let borrowed = &to_borrow;
|
||||||
let res = borrowed.len();
|
let res = borrowed.len();
|
||||||
|
|
||||||
// Tricks to actually get a self reference
|
// Trick to actually get a self reference
|
||||||
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
|
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
|
||||||
match self {
|
match self {
|
||||||
GeneratorA::Yield1{to_borrow, borrowed} => *borrowed = to_borrow,
|
GeneratorA::Yield1{to_borrow, borrowed} => *borrowed = to_borrow,
|
||||||
@@ -489,10 +489,10 @@ impl Generator for GeneratorA {
|
|||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>Try to uncomment the line with <code>mem::swap</code> and see the result of running this code.</p>
|
<p>Try to uncomment the line with <code>mem::swap</code> and see the results.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<p>While the example above compiles just fine, we expose users of this code to
|
<p>While the example above compiles just fine, we expose consumers of this this API
|
||||||
both possible undefined behavior and other memory errors while using just safe
|
to both possible undefined behavior and other memory errors while using just safe
|
||||||
Rust. This is a big problem!</p>
|
Rust. This is a big problem!</p>
|
||||||
<p>But now, let's prevent the segfault from happening using <code>Pin</code>. We'll discuss
|
<p>But now, let's prevent the segfault from happening using <code>Pin</code>. We'll discuss
|
||||||
<code>Pin</code> more below, but you'll get an introduction here by just reading the
|
<code>Pin</code> more below, but you'll get an introduction here by just reading the
|
||||||
@@ -608,15 +608,16 @@ impl Generator for GeneratorA {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>Now, as you see, the user of this code must either:</p>
|
<p>Now, as you see, the consumer of this API must either:</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Box the value and thereby allocating it on the heap</li>
|
<li>Box the value and thereby allocating it on the heap</li>
|
||||||
<li>Use <code>unsafe</code> and pin the value to the stack. The user knows that if they move
|
<li>Use <code>unsafe</code> and pin the value to the stack. The user knows that if they move
|
||||||
the value afterwards it will violate the guarantee they promise to uphold when
|
the value afterwards it will violate the guarantee they promise to uphold when
|
||||||
they did their unsafe implementation.</li>
|
they did their unsafe implementation.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Now, the code which is created and the need for <code>Pin</code> to allow for borrowing
|
<p>Hopefully, after this you'll have an idea of what happens when you use the
|
||||||
across <code>yield</code> points should be pretty clear.</p>
|
<code>yield</code> or <code>await</code> keyword (inside an async function) why we need <code>Pin</code> if we
|
||||||
|
want to be able to borrow across <code>yield/await</code> points.</p>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
@@ -199,7 +199,7 @@ Moving such a type can cause the universe to crash. As of the time of writing
|
|||||||
this book, creating an reading fields of a self referential struct still requires <code>unsafe</code>.</p>
|
this book, creating an reading fields of a self referential struct still requires <code>unsafe</code>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>You're not really meant to be implementing <code>MustStay</code>, but you can on nightly with a feature flag, or by adding <code>std::marker::PhantomPinned</code> to your type.</p>
|
<p>You can add a <code>MustStay</code> bound on a type by nightly with a feature flag, or by adding <code>std::marker::PhantomPinned</code> to your type.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>When Pinning, you can either pin a value to memory either on the stack or
|
<p>When Pinning, you can either pin a value to memory either on the stack or
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
@@ -523,8 +523,8 @@ fn main() {
|
|||||||
// - first parameter is the `reactor`
|
// - first parameter is the `reactor`
|
||||||
// - the second is a timeout in seconds
|
// - the second is a timeout in seconds
|
||||||
// - the third is an `id` to identify the task
|
// - the third is an `id` to identify the task
|
||||||
let future1 = Task::new(reactor.clone(), 2, 1);
|
let future1 = Task::new(reactor.clone(), 1, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
let future2 = Task::new(reactor.clone(), 2, 2);
|
||||||
|
|
||||||
// an `async` block works the same way as an `async fn` in that it compiles
|
// an `async` block works the same way as an `async fn` in that it compiles
|
||||||
// our code into a state machine, `yielding` at every `await` point.
|
// our code into a state machine, `yielding` at every `await` point.
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
@@ -165,8 +165,12 @@ fn main() {
|
|||||||
let reactor = Reactor::new();
|
let reactor = Reactor::new();
|
||||||
let reactor = Arc::new(Mutex::new(reactor));
|
let reactor = Arc::new(Mutex::new(reactor));
|
||||||
|
|
||||||
let future1 = Task::new(reactor.clone(), 2, 1);
|
let future1 = Task::new(reactor.clone(), 1, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let future2 = Task::new(reactor.clone(), 2, 2);
|
||||||
|
|
||||||
let fut1 = async {
|
let fut1 = async {
|
||||||
let val = future1.await;
|
let val = future1.await;
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
|
|||||||
@@ -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 and Pin</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> The 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_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> The 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>
|
||||||
@@ -455,7 +455,7 @@ a callback-based approach, where each closure stores all the data it needs
|
|||||||
for computation. This means that as we chain these, the memory required to store
|
for computation. This means that as we chain these, the memory required to store
|
||||||
the needed state increases with each added step.</p>
|
the needed state increases with each added step.</p>
|
||||||
<h3><a class="header" href="#stackless-coroutinesgenerators" id="stackless-coroutinesgenerators">Stackless coroutines/generators</a></h3>
|
<h3><a class="header" href="#stackless-coroutinesgenerators" id="stackless-coroutinesgenerators">Stackless coroutines/generators</a></h3>
|
||||||
<p>This is the model used in Rust today. It a few notable advantages:</p>
|
<p>This is the model used in Rust today. It has a few notable advantages:</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>It's easy to convert normal Rust code to a stackless coroutine using using
|
<li>It's easy to convert normal Rust code to a stackless coroutine using using
|
||||||
async/await as keywords (it can even be done using a macro).</li>
|
async/await as keywords (it can even be done using a macro).</li>
|
||||||
@@ -648,7 +648,7 @@ impl Generator for GeneratorA {
|
|||||||
<p>If you try to compile this you'll get an error (just try it yourself by pressing play).</p>
|
<p>If you try to compile this you'll get an error (just try it yourself by pressing play).</p>
|
||||||
<p>What is the lifetime of <code>&String</code>. It's not the same as the lifetime of <code>Self</code>. It's not <code>static</code>.
|
<p>What is the lifetime of <code>&String</code>. It's not the same as the lifetime of <code>Self</code>. It's not <code>static</code>.
|
||||||
Turns out that it's not possible for us in Rusts syntax to describe this lifetime, which means, that
|
Turns out that it's not possible for us in Rusts syntax to describe this lifetime, which means, that
|
||||||
to make this work, we'll have to let the compiler know that <em>we</em> control this correct.</p>
|
to make this work, we'll have to let the compiler know that <em>we</em> control this correctly ourselves.</p>
|
||||||
<p>That means turning to unsafe.</p>
|
<p>That means turning to unsafe.</p>
|
||||||
<p>Let's try to write an implementation that will compiler using <code>unsafe</code>. As you'll
|
<p>Let's try to write an implementation that will compiler using <code>unsafe</code>. As you'll
|
||||||
see we end up in a <em>self referential struct</em>. A struct which holds references
|
see we end up in a <em>self referential struct</em>. A struct which holds references
|
||||||
@@ -711,7 +711,7 @@ impl Generator for GeneratorA {
|
|||||||
let borrowed = &to_borrow;
|
let borrowed = &to_borrow;
|
||||||
let res = borrowed.len();
|
let res = borrowed.len();
|
||||||
|
|
||||||
// Tricks to actually get a self reference
|
// Trick to actually get a self reference
|
||||||
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
|
*self = GeneratorA::Yield1 {to_borrow, borrowed: std::ptr::null()};
|
||||||
match self {
|
match self {
|
||||||
GeneratorA::Yield1{to_borrow, borrowed} => *borrowed = to_borrow,
|
GeneratorA::Yield1{to_borrow, borrowed} => *borrowed = to_borrow,
|
||||||
@@ -733,10 +733,10 @@ impl Generator for GeneratorA {
|
|||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>Try to uncomment the line with <code>mem::swap</code> and see the result of running this code.</p>
|
<p>Try to uncomment the line with <code>mem::swap</code> and see the results.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
<p>While the example above compiles just fine, we expose users of this code to
|
<p>While the example above compiles just fine, we expose consumers of this this API
|
||||||
both possible undefined behavior and other memory errors while using just safe
|
to both possible undefined behavior and other memory errors while using just safe
|
||||||
Rust. This is a big problem!</p>
|
Rust. This is a big problem!</p>
|
||||||
<p>But now, let's prevent the segfault from happening using <code>Pin</code>. We'll discuss
|
<p>But now, let's prevent the segfault from happening using <code>Pin</code>. We'll discuss
|
||||||
<code>Pin</code> more below, but you'll get an introduction here by just reading the
|
<code>Pin</code> more below, but you'll get an introduction here by just reading the
|
||||||
@@ -852,15 +852,16 @@ impl Generator for GeneratorA {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</code></pre></pre>
|
</code></pre></pre>
|
||||||
<p>Now, as you see, the user of this code must either:</p>
|
<p>Now, as you see, the consumer of this API must either:</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Box the value and thereby allocating it on the heap</li>
|
<li>Box the value and thereby allocating it on the heap</li>
|
||||||
<li>Use <code>unsafe</code> and pin the value to the stack. The user knows that if they move
|
<li>Use <code>unsafe</code> and pin the value to the stack. The user knows that if they move
|
||||||
the value afterwards it will violate the guarantee they promise to uphold when
|
the value afterwards it will violate the guarantee they promise to uphold when
|
||||||
they did their unsafe implementation.</li>
|
they did their unsafe implementation.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Now, the code which is created and the need for <code>Pin</code> to allow for borrowing
|
<p>Hopefully, after this you'll have an idea of what happens when you use the
|
||||||
across <code>yield</code> points should be pretty clear.</p>
|
<code>yield</code> or <code>await</code> keyword (inside an async function) why we need <code>Pin</code> if we
|
||||||
|
want to be able to borrow across <code>yield/await</code> points.</p>
|
||||||
<h1><a class="header" href="#pin" id="pin">Pin</a></h1>
|
<h1><a class="header" href="#pin" id="pin">Pin</a></h1>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p><strong>Relevant for</strong></p>
|
<p><strong>Relevant for</strong></p>
|
||||||
@@ -911,7 +912,7 @@ Moving such a type can cause the universe to crash. As of the time of writing
|
|||||||
this book, creating an reading fields of a self referential struct still requires <code>unsafe</code>.</p>
|
this book, creating an reading fields of a self referential struct still requires <code>unsafe</code>.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>You're not really meant to be implementing <code>MustStay</code>, but you can on nightly with a feature flag, or by adding <code>std::marker::PhantomPinned</code> to your type.</p>
|
<p>You can add a <code>MustStay</code> bound on a type by nightly with a feature flag, or by adding <code>std::marker::PhantomPinned</code> to your type.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>When Pinning, you can either pin a value to memory either on the stack or
|
<p>When Pinning, you can either pin a value to memory either on the stack or
|
||||||
@@ -1504,8 +1505,8 @@ fn main() {
|
|||||||
// - first parameter is the `reactor`
|
// - first parameter is the `reactor`
|
||||||
// - the second is a timeout in seconds
|
// - the second is a timeout in seconds
|
||||||
// - the third is an `id` to identify the task
|
// - the third is an `id` to identify the task
|
||||||
let future1 = Task::new(reactor.clone(), 2, 1);
|
let future1 = Task::new(reactor.clone(), 1, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
let future2 = Task::new(reactor.clone(), 2, 2);
|
||||||
|
|
||||||
// an `async` block works the same way as an `async fn` in that it compiles
|
// an `async` block works the same way as an `async fn` in that it compiles
|
||||||
// our code into a state machine, `yielding` at every `await` point.
|
// our code into a state machine, `yielding` at every `await` point.
|
||||||
@@ -1802,8 +1803,12 @@ fn main() {
|
|||||||
let reactor = Reactor::new();
|
let reactor = Reactor::new();
|
||||||
let reactor = Arc::new(Mutex::new(reactor));
|
let reactor = Arc::new(Mutex::new(reactor));
|
||||||
|
|
||||||
let future1 = Task::new(reactor.clone(), 2, 1);
|
let future1 = Task::new(reactor.clone(), 1, 1);
|
||||||
let future2 = Task::new(reactor.clone(), 1, 2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let future2 = Task::new(reactor.clone(), 2, 2);
|
||||||
|
|
||||||
let fut1 = async {
|
let fut1 = async {
|
||||||
let val = future1.await;
|
let val = future1.await;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,9 +3,8 @@
|
|||||||
> **Relevant for:**
|
> **Relevant for:**
|
||||||
>
|
>
|
||||||
> - High level introduction to concurrency in Rust
|
> - High level introduction to concurrency in Rust
|
||||||
> - Knowing what Rust provides and not when working with async
|
> - Knowing what Rust provides and not when working with async code
|
||||||
> - Understanding why we need runtimes
|
> - Understanding why we need runtimes
|
||||||
> - Knowing that Rust has `Futures 1.0` and `Futures 3.0`, and how to deal with them
|
|
||||||
> - Getting pointers to further reading on concurrency in general
|
> - Getting pointers to further reading on concurrency in general
|
||||||
|
|
||||||
Before we start implementing our `Futures` , we'll go through some background
|
Before we start implementing our `Futures` , we'll go through some background
|
||||||
@@ -21,15 +20,17 @@ Let's get some of the common roadblocks out of the way first.
|
|||||||
Async in Rust is different from most other languages in the sense that Rust
|
Async in Rust is different from most other languages in the sense that Rust
|
||||||
has a very lightweight runtime.
|
has a very lightweight runtime.
|
||||||
|
|
||||||
In languages like C#, JavaScript, Java and GO, already includes a runtime
|
Languages like C#, JavaScript, Java and GO, already includes 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
|
||||||
seem a bit strange to you.
|
seem a bit strange to you.
|
||||||
|
|
||||||
|
In Rust you will have to make an active choice about which runtime to use.
|
||||||
|
|
||||||
### What Rust's standard library takes care of
|
### What Rust's standard library takes care of
|
||||||
|
|
||||||
1. The definition of an interruptible task
|
1. The definition of an interruptible task
|
||||||
2. An efficient technique to start, suspend, resume and store tasks
|
2. An efficient technique to start, suspend, resume and store tasks which are
|
||||||
which are executed concurrently.
|
executed concurrently.
|
||||||
3. A defined way to wake up a suspended task
|
3. A defined way to wake up a suspended task
|
||||||
|
|
||||||
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
|
||||||
@@ -48,18 +49,19 @@ an event queue and so on.
|
|||||||
|
|
||||||
Executors, accepts one or more asynchronous tasks called `Futures` and takes
|
Executors, accepts one or more asynchronous tasks called `Futures` and takes
|
||||||
care of actually running the code we write, suspend the tasks when they're
|
care of actually running the code we write, suspend the tasks when they're
|
||||||
waiting for I/O and resumes them.
|
waiting for I/O and resume them.
|
||||||
|
|
||||||
In theory, we could choose one `Reactor` and one `Executor` that have nothing
|
In theory, we could choose one `Reactor` and one `Executor` that have nothing
|
||||||
to do with each other besides one creates leaf `Futures` and one runs them, but
|
to do with each other besides that one creates leaf `Futures` and the other one
|
||||||
in reality today you'll most often get both in a `Runtime`.
|
runs them, but in reality today you'll most often get both in a `Runtime`.
|
||||||
|
|
||||||
There are mainly two such runtimes today [async_std][async_std] and [tokio][tokio].
|
There are mainly two such runtimes today [async_std][async_std] and [tokio][tokio].
|
||||||
|
|
||||||
Quite a bit of complexity attributed to `Futures` are actually complexity rooted
|
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
|
in runtimes. Creating an efficient runtime is hard.
|
||||||
correctly can be hard as well, but both are excellent and it's just like
|
|
||||||
learning any new library.
|
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
|
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
|
active choice when it comes to picking a runtime. Most often you'll just use
|
||||||
@@ -80,9 +82,10 @@ to know in advance.
|
|||||||
A good sign is that if you're required to use combinators like `and_then` then
|
A good sign is that if you're required to use combinators like `and_then` then
|
||||||
you're using `Futures 1.0`.
|
you're using `Futures 1.0`.
|
||||||
|
|
||||||
While not directly compatible, there is a tool that let's you relatively easily
|
While they're not directly compatible, there is a tool that let's you relatively
|
||||||
convert a `Future 1.0` to a `Future 3.0` and vice a versa. You can find all you
|
easily convert a `Future 1.0` to a `Future 3.0` and vice a versa. You can find
|
||||||
need in the [`futures-rs`][futures_rs] crate and all [information you need here][compat_info].
|
all you need in the [`futures-rs`][futures_rs] crate and all
|
||||||
|
[information you need here][compat_info].
|
||||||
|
|
||||||
## First things first
|
## First things first
|
||||||
|
|
||||||
@@ -96,13 +99,12 @@ try to give a high level overview that will make it easier to learn Rusts
|
|||||||
* [Async Basics - Strategies for handling I/O](https://cfsamson.github.io/book-exploring-async-basics/5_strategies_for_handling_io.html)
|
* [Async Basics - Strategies for handling I/O](https://cfsamson.github.io/book-exploring-async-basics/5_strategies_for_handling_io.html)
|
||||||
* [Async Basics - Epoll, Kqueue and IOCP](https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html)
|
* [Async Basics - Epoll, Kqueue and IOCP](https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html)
|
||||||
|
|
||||||
Now learning these concepts by studying futures is making it much harder than
|
Learning these concepts by studying futures is making it much harder than
|
||||||
it needs to be, so go on and read these chapters. I'll be right here when
|
it needs to be, so go on and read these chapters if you feel a bit unsure.
|
||||||
you're back.
|
|
||||||
|
|
||||||
However, if you feel that you have the basics covered, then go right on.
|
I'll be right here when you're back.
|
||||||
|
|
||||||
Let's get moving!
|
However, if you feel that you have the basics covered, then let's get moving!
|
||||||
|
|
||||||
[async_std]: https://github.com/async-rs/async-std
|
[async_std]: https://github.com/async-rs/async-std
|
||||||
[tokio]: https://github.com/tokio-rs/tokio
|
[tokio]: https://github.com/tokio-rs/tokio
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
## Trait objects and dynamic dispatch
|
## Trait objects and dynamic dispatch
|
||||||
|
|
||||||
One of the most confusing topic we encounter when implementing our own `Futures`
|
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`
|
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
|
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.
|
||||||
@@ -44,7 +44,7 @@ As you see from the output after running this, the sizes of the references varie
|
|||||||
Many are 8 bytes (which is a pointer size on 64 bit systems), but some are 16
|
Many are 8 bytes (which is a pointer size on 64 bit systems), but some are 16
|
||||||
bytes.
|
bytes.
|
||||||
|
|
||||||
The 16 byte sized pointers are called "fat pointers" since they carry more extra
|
The 16 byte sized pointers are called "fat pointers" since they carry extra
|
||||||
information.
|
information.
|
||||||
|
|
||||||
**Example `&[i32]` :**
|
**Example `&[i32]` :**
|
||||||
@@ -55,7 +55,7 @@ information.
|
|||||||
**Example `&dyn SomeTrait`:**
|
**Example `&dyn SomeTrait`:**
|
||||||
|
|
||||||
This is the type of fat pointer we'll concern ourselves about going forward.
|
This is the type of fat pointer we'll concern ourselves about going forward.
|
||||||
`&dyn SomeTrait` is a reference to a trait, or what Rust calls _trait objects_.
|
`&dyn SomeTrait` is a reference to a trait, or what Rust calls a _trait object_.
|
||||||
|
|
||||||
The layout for a pointer to a _trait object_ looks like this:
|
The layout for a pointer to a _trait object_ looks like this:
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ 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 allow 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:
|
||||||
|
|||||||
@@ -3,21 +3,20 @@
|
|||||||
>**Relevant for:**
|
>**Relevant for:**
|
||||||
>
|
>
|
||||||
>- Understanding how the async/await syntax works since it's how `await` is implemented
|
>- Understanding how the async/await syntax works since it's how `await` is implemented
|
||||||
>- Why we need `Pin`
|
>- Knowing why we need `Pin`
|
||||||
>- Why Rusts async model is very efficient
|
>- Understanding why Rusts async model is very efficient
|
||||||
>
|
>
|
||||||
>The motivation for `Generators` can be found in [RFC#2033][rfc2033]. It's very
|
>The motivation for `Generators` can be found in [RFC#2033][rfc2033]. It's very
|
||||||
>well written and I can recommend reading through it (it talks as much about
|
>well written and I can recommend reading through it (it talks as much about
|
||||||
>async/await as it does about generators).
|
>async/await as it does about generators).
|
||||||
|
|
||||||
The second difficult part that there seems to be a lot of questions about
|
The second difficult part is understanding Generators and the `Pin` type. Since
|
||||||
is Generators and the `Pin` type. Since they're related we'll start off by
|
they're related we'll start off by exploring generators first. By doing that
|
||||||
exploring generators first. By doing that we'll soon get to see why
|
we'll soon get to see why we need to be able to "pin" some data to a fixed
|
||||||
we need to be able to "pin" some data to a fixed location in memory and
|
location in memory and get an introduction to `Pin` as well.
|
||||||
get an introduction to `Pin` as well.
|
|
||||||
|
|
||||||
Basically, there were three main options that were discussed when Rust was
|
Basically, there were three main options discussed when designing how Rust would
|
||||||
designing how the language would handle concurrency:
|
handle concurrency:
|
||||||
|
|
||||||
1. Stackful coroutines, better known as green threads.
|
1. Stackful coroutines, better known as green threads.
|
||||||
2. Using combinators.
|
2. Using combinators.
|
||||||
@@ -29,9 +28,11 @@ I've written about green threads before. Go check out
|
|||||||
[Green Threads Explained in 200 lines of Rust][greenthreads] if you're interested.
|
[Green Threads Explained in 200 lines of Rust][greenthreads] if you're interested.
|
||||||
|
|
||||||
Green threads uses the same mechanisms as an OS does by creating a thread for
|
Green threads uses the same mechanisms as an OS does by creating a thread for
|
||||||
each task, setting up a stack, save the CPU's state and jump
|
each task, setting up a stack, save the CPU's state and jump from one
|
||||||
from one task(thread) to another by doing a "context switch". We yield control to the scheduler which then
|
task(thread) to another by doing a "context switch".
|
||||||
continues running a different task.
|
|
||||||
|
We yield control to the scheduler (which is a central part of the runtime in
|
||||||
|
such a system) which then continues running a different task.
|
||||||
|
|
||||||
Rust had green threads once, but they were removed before it hit 1.0. The state
|
Rust had green threads once, but they were removed before it hit 1.0. The state
|
||||||
of execution is stored in each stack so in such a solution there would be no need
|
of execution is stored in each stack so in such a solution there would be no need
|
||||||
|
|||||||
@@ -72,8 +72,15 @@ There are many great resources for further study. In addition to the RFCs and
|
|||||||
articles I've already linked to in the book, here are some of my suggestions:
|
articles I've already linked to in the book, here are some of my suggestions:
|
||||||
|
|
||||||
[The official Asyc book](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html)
|
[The official Asyc book](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html)
|
||||||
|
|
||||||
[The async_std book](https://book.async.rs/)
|
[The async_std book](https://book.async.rs/)
|
||||||
|
|
||||||
[Aron Turon: Designing futures for Rust](https://aturon.github.io/blog/2016/09/07/futures-design/)
|
[Aron Turon: Designing futures for Rust](https://aturon.github.io/blog/2016/09/07/futures-design/)
|
||||||
|
|
||||||
[Steve Klabnik's presentation: Rust's journey to Async/Await](https://www.infoq.com/presentations/rust-2019/)
|
[Steve Klabnik's presentation: Rust's journey to Async/Await](https://www.infoq.com/presentations/rust-2019/)
|
||||||
|
|
||||||
[The Tokio Blog](https://tokio.rs/blog/2019-10-scheduler/)
|
[The Tokio Blog](https://tokio.rs/blog/2019-10-scheduler/)
|
||||||
|
|
||||||
[Stjepan's blog with a series where he implements an Executor](https://stjepang.github.io/)
|
[Stjepan's blog with a series where he implements an Executor](https://stjepang.github.io/)
|
||||||
|
|
||||||
|
[Jon Gjengset's video on The Why, What and How of Pinning in Rust](https://youtu.be/DkMwYxfSYNQ)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ The goal is to get a better understanding of `Futures` by implementing a toy
|
|||||||
We'll start off a bit differently than most other explanations. Instead of
|
We'll start off a bit differently than most other explanations. Instead of
|
||||||
deferring some of the details about what's special about futures in Rust we
|
deferring some of the details about what's special about futures in Rust we
|
||||||
try to tackle that head on first. We'll be as brief as possible, but as thorough
|
try to tackle that head on first. We'll be as brief as possible, but as thorough
|
||||||
as needed. This way, most question will be answered and explored up front.
|
as needed. This way, most questions will be answered and explored up front.
|
||||||
|
|
||||||
We'll end up with futures that can run an any executor like `tokio` and `async_str`.
|
We'll end up with futures that can run an any executor like `tokio` and `async_str`.
|
||||||
|
|
||||||
@@ -27,8 +27,11 @@ of all, this book will focus on `Futures` and `async/await` specifically and
|
|||||||
not in the context of any specific runtime.
|
not in the context of any specific runtime.
|
||||||
|
|
||||||
Secondly, I've always found small runnable examples very exiting to learn from.
|
Secondly, I've always found small runnable examples very exiting to learn from.
|
||||||
Thanks to [Mdbook][mdbook] the examples can even be edited and explored further. It's
|
Thanks to [Mdbook][mdbook] the examples can even be edited and explored further
|
||||||
all code that you can download, play with and learn from.
|
by uncommenting certain lines or adding new ones yourself. I use that quite a
|
||||||
|
but throughout so keep an eye out when reading through editable code segments.
|
||||||
|
|
||||||
|
It's all code that you can download, play with and learn from.
|
||||||
|
|
||||||
We'll and end up with an understandable example including a `Future`
|
We'll and end up with an understandable example including a `Future`
|
||||||
implementation, an `Executor` and a `Reactor` in less than 200 lines of code.
|
implementation, an `Executor` and a `Reactor` in less than 200 lines of code.
|
||||||
|
|||||||
Reference in New Issue
Block a user