audit pass introduction and background_information
This commit is contained in:
@@ -153,8 +153,8 @@
|
||||
<p>Before we go into the details about Futures in Rust, let's take a quick look
|
||||
at the alternatives for handling concurrent programming in general and some
|
||||
pros and cons for each of them.</p>
|
||||
<p>While we do that we'll get some information on concurrency which will make it
|
||||
easier for us when we dive in to Futures specifically.</p>
|
||||
<p>While we do that we'll also explain some aspects when it comes to concurrency which
|
||||
will make it easier for us when we dive in to Futures specifically.</p>
|
||||
<blockquote>
|
||||
<p>For fun, I've added a small snipped of runnable code with most of the examples.
|
||||
If you're like me, things get way more interesting then and maybe you'll se some
|
||||
@@ -210,7 +210,7 @@ fn main() {
|
||||
</code></pre></pre>
|
||||
<p>OS threads sure has some pretty big advantages. So why all this talk about
|
||||
"async" and concurrency in the first place?</p>
|
||||
<p>First of all. For computers to be <a href="https://en.wikipedia.org/wiki/Efficiency"><em>efficient</em></a> it needs to multitask. Once you
|
||||
<p>First of all. For computers to be <a href="https://en.wikipedia.org/wiki/Efficiency"><em>efficient</em></a> they needs to multitask. Once you
|
||||
start to look under the covers (like <a href="https://os.phil-opp.com/async-await/">how an operating system works</a>)
|
||||
you'll see concurrency everywhere. It's very fundamental in everything we do.</p>
|
||||
<p>Secondly, we have the web. </p>
|
||||
@@ -218,10 +218,9 @@ you'll see concurrency everywhere. It's very fundamental in everything we do.</p
|
||||
(requests). When the number of small tasks is large it's not a good fit for OS
|
||||
threads as of today because of the memory they require and the overhead involved
|
||||
when creating new threads. </p>
|
||||
<p>This gets even more relevant when the load is variable
|
||||
which means the current number of tasks a program has at any point in time is
|
||||
unpredictable. That's why you'll see so many async web frameworks and database
|
||||
drivers today.</p>
|
||||
<p>This gets even more problematic when the load is variable which means the current number of tasks a
|
||||
program has at any point in time is unpredictable. That's why you'll see so many async web
|
||||
frameworks and database drivers today.</p>
|
||||
<p>However, for a huge number of problems, the standard OS threads will often be the
|
||||
right solution. So, just think twice about your problem before you reach for an
|
||||
async library.</p>
|
||||
@@ -237,15 +236,16 @@ such a system) which then continues running a different task.</p>
|
||||
<p>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 for <code>async</code>, <code>await</code>, <code>Futures</code> or <code>Pin</code>. </p>
|
||||
<p>The typical flow will be like this:</p>
|
||||
<p><strong>The typical flow looks like this:</strong></p>
|
||||
<ol>
|
||||
<li>Run som non-blocking code</li>
|
||||
<li>Run some non-blocking code</li>
|
||||
<li>Make a blocking call to some external resource</li>
|
||||
<li>CPU jumps to the "main" thread which schedules a different thread to run and
|
||||
"jumps" to that stack</li>
|
||||
<li>Run some non-blocking code on the new thread until a new blocking call or the
|
||||
task is finished</li>
|
||||
<li>"jumps" back to the "main" thread, schedule a new thread to run and jump to that</li>
|
||||
<li>"jumps" back to the "main" thread, schedule a new thread which is ready to make
|
||||
progress and jump to that.</li>
|
||||
</ol>
|
||||
<p>These "jumps" are know as <strong>context switches</strong>. Your OS is doing it many times each
|
||||
second as you read this.</p>
|
||||
@@ -501,16 +501,17 @@ in life, close your eyes now and scroll down for 2-3 seconds. You'll find a link
|
||||
there that takes you to safety.</p>
|
||||
</blockquote>
|
||||
<p>The whole idea behind a callback based approach is to save a pointer to a set of
|
||||
instructions we want to run later. We can save that pointer on the stack before
|
||||
we yield control to the runtime, or in some sort of collection as we do below.</p>
|
||||
<p>The basic idea of not involving threads as a primary way to achieve concurrency
|
||||
instructions we want to run later together with whatever state is needed. In rust this
|
||||
would be a <code>closure</code>. In the example below, we save this information in a <code>HashMap</code>
|
||||
but it's not the only option.</p>
|
||||
<p>The basic idea of <em>not</em> involving threads as a primary way to achieve concurrency
|
||||
is the common denominator for the rest of the approaches. Including the one
|
||||
Rust uses today which we'll soon get to.</p>
|
||||
<p><strong>Advantages:</strong></p>
|
||||
<ul>
|
||||
<li>Easy to implement in most languages</li>
|
||||
<li>No context switching</li>
|
||||
<li>Low memory overhead (in most cases)</li>
|
||||
<li>Relatively low memory overhead (in most cases)</li>
|
||||
</ul>
|
||||
<p><strong>Drawbacks:</strong></p>
|
||||
<ul>
|
||||
@@ -594,10 +595,10 @@ impl Runtime {
|
||||
</code></pre></pre>
|
||||
<p>We're keeping this super simple, and you might wonder what's the difference
|
||||
between this approach and the one using OS threads an passing in the callbacks
|
||||
to the OS threads directly. </p>
|
||||
to the OS threads directly.</p>
|
||||
<p>The difference is that the callbacks are run on the
|
||||
same thread using this example. The OS threads we create are basically just used
|
||||
as timers.</p>
|
||||
as timers but could represent any kind of resource that we'll have to wait for.</p>
|
||||
<h2><a class="header" href="#from-callbacks-to-promises" id="from-callbacks-to-promises">From callbacks to promises</a></h2>
|
||||
<p>You might start to wonder by now, when are we going to talk about Futures?</p>
|
||||
<p>Well, we're getting there. You see <code>promises</code>, <code>futures</code> and other names for
|
||||
@@ -652,7 +653,7 @@ Rusts Futures 3.0 is a lot like async/await in our last example.</p>
|
||||
go through all this is to get an introduction and get into the right mindset for
|
||||
exploring Rusts Futures.</p>
|
||||
<blockquote>
|
||||
<p>To avoid confusion later on: There is one difference you should know. Javascript
|
||||
<p>To avoid confusion later on: There's one difference you should know. Javascript
|
||||
promises are <em>eagerly</em> evaluated. That means that once it's created, it starts
|
||||
running a task. Rusts Futures on the other hand is <em>lazily</em> evaluated. They
|
||||
need to be polled once before they do any work.</p>
|
||||
|
||||
43
book/ace.js
43
book/ace.js
File diff suppressed because one or more lines are too long
BIN
book/assets/reactorexecutor.png
Normal file
BIN
book/assets/reactorexecutor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
BIN
book/assets/swap_problem.jpg
Normal file
BIN
book/assets/swap_problem.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
10
book/elasticlunr.min.js
vendored
Normal file
10
book/elasticlunr.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -151,8 +151,9 @@
|
||||
<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>
|
||||
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach,
|
||||
exploring why they're designed the way they are, the alternatives and how
|
||||
they work.</p>
|
||||
exploring why they're designed the way they are, and how they work. We'll also
|
||||
take a look at some of the alternatives we have when dealing with concurrency
|
||||
in programming.</p>
|
||||
<p>Going into the level of detail I do in this book is not needed to use futures
|
||||
or async/await in Rust. It's for the curious out there that want to know <em>how</em>
|
||||
it all works.</p>
|
||||
@@ -162,9 +163,8 @@ topic of different types of executors and runtimes. We'll just implement a very
|
||||
simple runtime in this book introducing some concepts but it's enough to get
|
||||
started.</p>
|
||||
<p><a href="https://github.com/stjepang">Stjepan Glavina</a> has made an excellent series of
|
||||
articles about async runtimes and executors, and if the rumors are right he's
|
||||
even working on a new async runtime that should be easy enough to use as
|
||||
learning material.</p>
|
||||
articles about async runtimes and executors, and if the rumors are right there
|
||||
is more to come from him in the near future.</p>
|
||||
<p>The way you should go about it is to read this book first, then continue
|
||||
reading the <a href="https://stjepang.github.io/">articles from stejpang</a> to learn more
|
||||
about runtimes and how they work, especially:</p>
|
||||
@@ -182,6 +182,7 @@ take everything step by step so get a cup of tea and relax. </p>
|
||||
<a href="https://github.com/cfsamson/books-futures-explained">the repository for the book itself here</a>. The final example which
|
||||
you can clone, fork or copy <a href="https://github.com/cfsamson/examples-futures">can be found here</a>. Any suggestions
|
||||
or improvements can be filed as a PR or in the issue tracker for the book.</p>
|
||||
<p>As always, all kinds of feedback is welcome.</p>
|
||||
</blockquote>
|
||||
<h2><a class="header" href="#reader-exercises-and-further-reading" id="reader-exercises-and-further-reading">Reader exercises and further reading</a></h2>
|
||||
<p>In the last <a href="conclusion.html">chapter</a> I've taken the liberty to suggest some
|
||||
|
||||
@@ -151,8 +151,9 @@
|
||||
<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>
|
||||
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach,
|
||||
exploring why they're designed the way they are, the alternatives and how
|
||||
they work.</p>
|
||||
exploring why they're designed the way they are, and how they work. We'll also
|
||||
take a look at some of the alternatives we have when dealing with concurrency
|
||||
in programming.</p>
|
||||
<p>Going into the level of detail I do in this book is not needed to use futures
|
||||
or async/await in Rust. It's for the curious out there that want to know <em>how</em>
|
||||
it all works.</p>
|
||||
@@ -162,9 +163,8 @@ topic of different types of executors and runtimes. We'll just implement a very
|
||||
simple runtime in this book introducing some concepts but it's enough to get
|
||||
started.</p>
|
||||
<p><a href="https://github.com/stjepang">Stjepan Glavina</a> has made an excellent series of
|
||||
articles about async runtimes and executors, and if the rumors are right he's
|
||||
even working on a new async runtime that should be easy enough to use as
|
||||
learning material.</p>
|
||||
articles about async runtimes and executors, and if the rumors are right there
|
||||
is more to come from him in the near future.</p>
|
||||
<p>The way you should go about it is to read this book first, then continue
|
||||
reading the <a href="https://stjepang.github.io/">articles from stejpang</a> to learn more
|
||||
about runtimes and how they work, especially:</p>
|
||||
@@ -182,6 +182,7 @@ take everything step by step so get a cup of tea and relax. </p>
|
||||
<a href="https://github.com/cfsamson/books-futures-explained">the repository for the book itself here</a>. The final example which
|
||||
you can clone, fork or copy <a href="https://github.com/cfsamson/examples-futures">can be found here</a>. Any suggestions
|
||||
or improvements can be filed as a PR or in the issue tracker for the book.</p>
|
||||
<p>As always, all kinds of feedback is welcome.</p>
|
||||
</blockquote>
|
||||
<h2><a class="header" href="#reader-exercises-and-further-reading" id="reader-exercises-and-further-reading">Reader exercises and further reading</a></h2>
|
||||
<p>In the last <a href="conclusion.html">chapter</a> I've taken the liberty to suggest some
|
||||
|
||||
7
book/mark.min.js
vendored
Normal file
7
book/mark.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
book/mode-rust.js
Normal file
7
book/mode-rust.js
Normal file
File diff suppressed because one or more lines are too long
@@ -153,8 +153,9 @@
|
||||
<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>
|
||||
<p>This book aims to explain <code>Futures</code> in Rust using an example driven approach,
|
||||
exploring why they're designed the way they are, the alternatives and how
|
||||
they work.</p>
|
||||
exploring why they're designed the way they are, and how they work. We'll also
|
||||
take a look at some of the alternatives we have when dealing with concurrency
|
||||
in programming.</p>
|
||||
<p>Going into the level of detail I do in this book is not needed to use futures
|
||||
or async/await in Rust. It's for the curious out there that want to know <em>how</em>
|
||||
it all works.</p>
|
||||
@@ -164,9 +165,8 @@ topic of different types of executors and runtimes. We'll just implement a very
|
||||
simple runtime in this book introducing some concepts but it's enough to get
|
||||
started.</p>
|
||||
<p><a href="https://github.com/stjepang">Stjepan Glavina</a> has made an excellent series of
|
||||
articles about async runtimes and executors, and if the rumors are right he's
|
||||
even working on a new async runtime that should be easy enough to use as
|
||||
learning material.</p>
|
||||
articles about async runtimes and executors, and if the rumors are right there
|
||||
is more to come from him in the near future.</p>
|
||||
<p>The way you should go about it is to read this book first, then continue
|
||||
reading the <a href="https://stjepang.github.io/">articles from stejpang</a> to learn more
|
||||
about runtimes and how they work, especially:</p>
|
||||
@@ -184,6 +184,7 @@ take everything step by step so get a cup of tea and relax. </p>
|
||||
<a href="https://github.com/cfsamson/books-futures-explained">the repository for the book itself here</a>. The final example which
|
||||
you can clone, fork or copy <a href="https://github.com/cfsamson/examples-futures">can be found here</a>. Any suggestions
|
||||
or improvements can be filed as a PR or in the issue tracker for the book.</p>
|
||||
<p>As always, all kinds of feedback is welcome.</p>
|
||||
</blockquote>
|
||||
<h2><a class="header" href="#reader-exercises-and-further-reading" id="reader-exercises-and-further-reading">Reader exercises and further reading</a></h2>
|
||||
<p>In the last <a href="conclusion.html">chapter</a> I've taken the liberty to suggest some
|
||||
@@ -206,8 +207,8 @@ finished product and has in no way endorsed it, but a thanks is definitely due.<
|
||||
<p>Before we go into the details about Futures in Rust, let's take a quick look
|
||||
at the alternatives for handling concurrent programming in general and some
|
||||
pros and cons for each of them.</p>
|
||||
<p>While we do that we'll get some information on concurrency which will make it
|
||||
easier for us when we dive in to Futures specifically.</p>
|
||||
<p>While we do that we'll also explain some aspects when it comes to concurrency which
|
||||
will make it easier for us when we dive in to Futures specifically.</p>
|
||||
<blockquote>
|
||||
<p>For fun, I've added a small snipped of runnable code with most of the examples.
|
||||
If you're like me, things get way more interesting then and maybe you'll se some
|
||||
@@ -263,7 +264,7 @@ fn main() {
|
||||
</code></pre></pre>
|
||||
<p>OS threads sure has some pretty big advantages. So why all this talk about
|
||||
"async" and concurrency in the first place?</p>
|
||||
<p>First of all. For computers to be <a href="https://en.wikipedia.org/wiki/Efficiency"><em>efficient</em></a> it needs to multitask. Once you
|
||||
<p>First of all. For computers to be <a href="https://en.wikipedia.org/wiki/Efficiency"><em>efficient</em></a> they needs to multitask. Once you
|
||||
start to look under the covers (like <a href="https://os.phil-opp.com/async-await/">how an operating system works</a>)
|
||||
you'll see concurrency everywhere. It's very fundamental in everything we do.</p>
|
||||
<p>Secondly, we have the web. </p>
|
||||
@@ -271,10 +272,9 @@ you'll see concurrency everywhere. It's very fundamental in everything we do.</p
|
||||
(requests). When the number of small tasks is large it's not a good fit for OS
|
||||
threads as of today because of the memory they require and the overhead involved
|
||||
when creating new threads. </p>
|
||||
<p>This gets even more relevant when the load is variable
|
||||
which means the current number of tasks a program has at any point in time is
|
||||
unpredictable. That's why you'll see so many async web frameworks and database
|
||||
drivers today.</p>
|
||||
<p>This gets even more problematic when the load is variable which means the current number of tasks a
|
||||
program has at any point in time is unpredictable. That's why you'll see so many async web
|
||||
frameworks and database drivers today.</p>
|
||||
<p>However, for a huge number of problems, the standard OS threads will often be the
|
||||
right solution. So, just think twice about your problem before you reach for an
|
||||
async library.</p>
|
||||
@@ -290,15 +290,16 @@ such a system) which then continues running a different task.</p>
|
||||
<p>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 for <code>async</code>, <code>await</code>, <code>Futures</code> or <code>Pin</code>. </p>
|
||||
<p>The typical flow will be like this:</p>
|
||||
<p><strong>The typical flow looks like this:</strong></p>
|
||||
<ol>
|
||||
<li>Run som non-blocking code</li>
|
||||
<li>Run some non-blocking code</li>
|
||||
<li>Make a blocking call to some external resource</li>
|
||||
<li>CPU jumps to the "main" thread which schedules a different thread to run and
|
||||
"jumps" to that stack</li>
|
||||
<li>Run some non-blocking code on the new thread until a new blocking call or the
|
||||
task is finished</li>
|
||||
<li>"jumps" back to the "main" thread, schedule a new thread to run and jump to that</li>
|
||||
<li>"jumps" back to the "main" thread, schedule a new thread which is ready to make
|
||||
progress and jump to that.</li>
|
||||
</ol>
|
||||
<p>These "jumps" are know as <strong>context switches</strong>. Your OS is doing it many times each
|
||||
second as you read this.</p>
|
||||
@@ -554,16 +555,17 @@ in life, close your eyes now and scroll down for 2-3 seconds. You'll find a link
|
||||
there that takes you to safety.</p>
|
||||
</blockquote>
|
||||
<p>The whole idea behind a callback based approach is to save a pointer to a set of
|
||||
instructions we want to run later. We can save that pointer on the stack before
|
||||
we yield control to the runtime, or in some sort of collection as we do below.</p>
|
||||
<p>The basic idea of not involving threads as a primary way to achieve concurrency
|
||||
instructions we want to run later together with whatever state is needed. In rust this
|
||||
would be a <code>closure</code>. In the example below, we save this information in a <code>HashMap</code>
|
||||
but it's not the only option.</p>
|
||||
<p>The basic idea of <em>not</em> involving threads as a primary way to achieve concurrency
|
||||
is the common denominator for the rest of the approaches. Including the one
|
||||
Rust uses today which we'll soon get to.</p>
|
||||
<p><strong>Advantages:</strong></p>
|
||||
<ul>
|
||||
<li>Easy to implement in most languages</li>
|
||||
<li>No context switching</li>
|
||||
<li>Low memory overhead (in most cases)</li>
|
||||
<li>Relatively low memory overhead (in most cases)</li>
|
||||
</ul>
|
||||
<p><strong>Drawbacks:</strong></p>
|
||||
<ul>
|
||||
@@ -647,10 +649,10 @@ impl Runtime {
|
||||
</code></pre></pre>
|
||||
<p>We're keeping this super simple, and you might wonder what's the difference
|
||||
between this approach and the one using OS threads an passing in the callbacks
|
||||
to the OS threads directly. </p>
|
||||
to the OS threads directly.</p>
|
||||
<p>The difference is that the callbacks are run on the
|
||||
same thread using this example. The OS threads we create are basically just used
|
||||
as timers.</p>
|
||||
as timers but could represent any kind of resource that we'll have to wait for.</p>
|
||||
<h2><a class="header" href="#from-callbacks-to-promises" id="from-callbacks-to-promises">From callbacks to promises</a></h2>
|
||||
<p>You might start to wonder by now, when are we going to talk about Futures?</p>
|
||||
<p>Well, we're getting there. You see <code>promises</code>, <code>futures</code> and other names for
|
||||
@@ -705,7 +707,7 @@ Rusts Futures 3.0 is a lot like async/await in our last example.</p>
|
||||
go through all this is to get an introduction and get into the right mindset for
|
||||
exploring Rusts Futures.</p>
|
||||
<blockquote>
|
||||
<p>To avoid confusion later on: There is one difference you should know. Javascript
|
||||
<p>To avoid confusion later on: There's one difference you should know. Javascript
|
||||
promises are <em>eagerly</em> evaluated. That means that once it's created, it starts
|
||||
running a task. Rusts Futures on the other hand is <em>lazily</em> evaluated. They
|
||||
need to be polled once before they do any work.</p>
|
||||
|
||||
477
book/searcher.js
Normal file
477
book/searcher.js
Normal file
@@ -0,0 +1,477 @@
|
||||
"use strict";
|
||||
window.search = window.search || {};
|
||||
(function search(search) {
|
||||
// Search functionality
|
||||
//
|
||||
// You can use !hasFocus() to prevent keyhandling in your key
|
||||
// event handlers while the user is typing their search.
|
||||
|
||||
if (!Mark || !elasticlunr) {
|
||||
return;
|
||||
}
|
||||
|
||||
//IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function(search, pos) {
|
||||
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
|
||||
};
|
||||
}
|
||||
|
||||
var search_wrap = document.getElementById('search-wrapper'),
|
||||
searchbar = document.getElementById('searchbar'),
|
||||
searchbar_outer = document.getElementById('searchbar-outer'),
|
||||
searchresults = document.getElementById('searchresults'),
|
||||
searchresults_outer = document.getElementById('searchresults-outer'),
|
||||
searchresults_header = document.getElementById('searchresults-header'),
|
||||
searchicon = document.getElementById('search-toggle'),
|
||||
content = document.getElementById('content'),
|
||||
|
||||
searchindex = null,
|
||||
doc_urls = [],
|
||||
results_options = {
|
||||
teaser_word_count: 30,
|
||||
limit_results: 30,
|
||||
},
|
||||
search_options = {
|
||||
bool: "AND",
|
||||
expand: true,
|
||||
fields: {
|
||||
title: {boost: 1},
|
||||
body: {boost: 1},
|
||||
breadcrumbs: {boost: 0}
|
||||
}
|
||||
},
|
||||
mark_exclude = [],
|
||||
marker = new Mark(content),
|
||||
current_searchterm = "",
|
||||
URL_SEARCH_PARAM = 'search',
|
||||
URL_MARK_PARAM = 'highlight',
|
||||
teaser_count = 0,
|
||||
|
||||
SEARCH_HOTKEY_KEYCODE = 83,
|
||||
ESCAPE_KEYCODE = 27,
|
||||
DOWN_KEYCODE = 40,
|
||||
UP_KEYCODE = 38,
|
||||
SELECT_KEYCODE = 13;
|
||||
|
||||
function hasFocus() {
|
||||
return searchbar === document.activeElement;
|
||||
}
|
||||
|
||||
function removeChildren(elem) {
|
||||
while (elem.firstChild) {
|
||||
elem.removeChild(elem.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to parse a url into its building blocks.
|
||||
function parseURL(url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
return {
|
||||
source: url,
|
||||
protocol: a.protocol.replace(':',''),
|
||||
host: a.hostname,
|
||||
port: a.port,
|
||||
params: (function(){
|
||||
var ret = {};
|
||||
var seg = a.search.replace(/^\?/,'').split('&');
|
||||
var len = seg.length, i = 0, s;
|
||||
for (;i<len;i++) {
|
||||
if (!seg[i]) { continue; }
|
||||
s = seg[i].split('=');
|
||||
ret[s[0]] = s[1];
|
||||
}
|
||||
return ret;
|
||||
})(),
|
||||
file: (a.pathname.match(/\/([^/?#]+)$/i) || [,''])[1],
|
||||
hash: a.hash.replace('#',''),
|
||||
path: a.pathname.replace(/^([^/])/,'/$1')
|
||||
};
|
||||
}
|
||||
|
||||
// Helper to recreate a url string from its building blocks.
|
||||
function renderURL(urlobject) {
|
||||
var url = urlobject.protocol + "://" + urlobject.host;
|
||||
if (urlobject.port != "") {
|
||||
url += ":" + urlobject.port;
|
||||
}
|
||||
url += urlobject.path;
|
||||
var joiner = "?";
|
||||
for(var prop in urlobject.params) {
|
||||
if(urlobject.params.hasOwnProperty(prop)) {
|
||||
url += joiner + prop + "=" + urlobject.params[prop];
|
||||
joiner = "&";
|
||||
}
|
||||
}
|
||||
if (urlobject.hash != "") {
|
||||
url += "#" + urlobject.hash;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
// Helper to escape html special chars for displaying the teasers
|
||||
var escapeHTML = (function() {
|
||||
var MAP = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
var repl = function(c) { return MAP[c]; };
|
||||
return function(s) {
|
||||
return s.replace(/[&<>'"]/g, repl);
|
||||
};
|
||||
})();
|
||||
|
||||
function formatSearchMetric(count, searchterm) {
|
||||
if (count == 1) {
|
||||
return count + " search result for '" + searchterm + "':";
|
||||
} else if (count == 0) {
|
||||
return "No search results for '" + searchterm + "'.";
|
||||
} else {
|
||||
return count + " search results for '" + searchterm + "':";
|
||||
}
|
||||
}
|
||||
|
||||
function formatSearchResult(result, searchterms) {
|
||||
var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms);
|
||||
teaser_count++;
|
||||
|
||||
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
|
||||
var url = doc_urls[result.ref].split("#");
|
||||
if (url.length == 1) { // no anchor found
|
||||
url.push("");
|
||||
}
|
||||
|
||||
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
|
||||
+ '" aria-details="teaser_' + teaser_count + '">' + result.doc.breadcrumbs + '</a>'
|
||||
+ '<span class="teaser" id="teaser_' + teaser_count + '" aria-label="Search Result Teaser">'
|
||||
+ teaser + '</span>';
|
||||
}
|
||||
|
||||
function makeTeaser(body, searchterms) {
|
||||
// The strategy is as follows:
|
||||
// First, assign a value to each word in the document:
|
||||
// Words that correspond to search terms (stemmer aware): 40
|
||||
// Normal words: 2
|
||||
// First word in a sentence: 8
|
||||
// Then use a sliding window with a constant number of words and count the
|
||||
// sum of the values of the words within the window. Then use the window that got the
|
||||
// maximum sum. If there are multiple maximas, then get the last one.
|
||||
// Enclose the terms in <em>.
|
||||
var stemmed_searchterms = searchterms.map(function(w) {
|
||||
return elasticlunr.stemmer(w.toLowerCase());
|
||||
});
|
||||
var searchterm_weight = 40;
|
||||
var weighted = []; // contains elements of ["word", weight, index_in_document]
|
||||
// split in sentences, then words
|
||||
var sentences = body.toLowerCase().split('. ');
|
||||
var index = 0;
|
||||
var value = 0;
|
||||
var searchterm_found = false;
|
||||
for (var sentenceindex in sentences) {
|
||||
var words = sentences[sentenceindex].split(' ');
|
||||
value = 8;
|
||||
for (var wordindex in words) {
|
||||
var word = words[wordindex];
|
||||
if (word.length > 0) {
|
||||
for (var searchtermindex in stemmed_searchterms) {
|
||||
if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) {
|
||||
value = searchterm_weight;
|
||||
searchterm_found = true;
|
||||
}
|
||||
};
|
||||
weighted.push([word, value, index]);
|
||||
value = 2;
|
||||
}
|
||||
index += word.length;
|
||||
index += 1; // ' ' or '.' if last word in sentence
|
||||
};
|
||||
index += 1; // because we split at a two-char boundary '. '
|
||||
};
|
||||
|
||||
if (weighted.length == 0) {
|
||||
return body;
|
||||
}
|
||||
|
||||
var window_weight = [];
|
||||
var window_size = Math.min(weighted.length, results_options.teaser_word_count);
|
||||
|
||||
var cur_sum = 0;
|
||||
for (var wordindex = 0; wordindex < window_size; wordindex++) {
|
||||
cur_sum += weighted[wordindex][1];
|
||||
};
|
||||
window_weight.push(cur_sum);
|
||||
for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) {
|
||||
cur_sum -= weighted[wordindex][1];
|
||||
cur_sum += weighted[wordindex + window_size][1];
|
||||
window_weight.push(cur_sum);
|
||||
};
|
||||
|
||||
if (searchterm_found) {
|
||||
var max_sum = 0;
|
||||
var max_sum_window_index = 0;
|
||||
// backwards
|
||||
for (var i = window_weight.length - 1; i >= 0; i--) {
|
||||
if (window_weight[i] > max_sum) {
|
||||
max_sum = window_weight[i];
|
||||
max_sum_window_index = i;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
max_sum_window_index = 0;
|
||||
}
|
||||
|
||||
// add <em/> around searchterms
|
||||
var teaser_split = [];
|
||||
var index = weighted[max_sum_window_index][2];
|
||||
for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) {
|
||||
var word = weighted[i];
|
||||
if (index < word[2]) {
|
||||
// missing text from index to start of `word`
|
||||
teaser_split.push(body.substring(index, word[2]));
|
||||
index = word[2];
|
||||
}
|
||||
if (word[1] == searchterm_weight) {
|
||||
teaser_split.push("<em>")
|
||||
}
|
||||
index = word[2] + word[0].length;
|
||||
teaser_split.push(body.substring(word[2], index));
|
||||
if (word[1] == searchterm_weight) {
|
||||
teaser_split.push("</em>")
|
||||
}
|
||||
};
|
||||
|
||||
return teaser_split.join('');
|
||||
}
|
||||
|
||||
function init(config) {
|
||||
results_options = config.results_options;
|
||||
search_options = config.search_options;
|
||||
searchbar_outer = config.searchbar_outer;
|
||||
doc_urls = config.doc_urls;
|
||||
searchindex = elasticlunr.Index.load(config.index);
|
||||
|
||||
// Set up events
|
||||
searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false);
|
||||
searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false);
|
||||
document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false);
|
||||
// If the user uses the browser buttons, do the same as if a reload happened
|
||||
window.onpopstate = function(e) { doSearchOrMarkFromUrl(); };
|
||||
// Suppress "submit" events so the page doesn't reload when the user presses Enter
|
||||
document.addEventListener('submit', function(e) { e.preventDefault(); }, false);
|
||||
|
||||
// If reloaded, do the search or mark again, depending on the current url parameters
|
||||
doSearchOrMarkFromUrl();
|
||||
}
|
||||
|
||||
function unfocusSearchbar() {
|
||||
// hacky, but just focusing a div only works once
|
||||
var tmp = document.createElement('input');
|
||||
tmp.setAttribute('style', 'position: absolute; opacity: 0;');
|
||||
searchicon.appendChild(tmp);
|
||||
tmp.focus();
|
||||
tmp.remove();
|
||||
}
|
||||
|
||||
// On reload or browser history backwards/forwards events, parse the url and do search or mark
|
||||
function doSearchOrMarkFromUrl() {
|
||||
// Check current URL for search request
|
||||
var url = parseURL(window.location.href);
|
||||
if (url.params.hasOwnProperty(URL_SEARCH_PARAM)
|
||||
&& url.params[URL_SEARCH_PARAM] != "") {
|
||||
showSearch(true);
|
||||
searchbar.value = decodeURIComponent(
|
||||
(url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20'));
|
||||
searchbarKeyUpHandler(); // -> doSearch()
|
||||
} else {
|
||||
showSearch(false);
|
||||
}
|
||||
|
||||
if (url.params.hasOwnProperty(URL_MARK_PARAM)) {
|
||||
var words = url.params[URL_MARK_PARAM].split(' ');
|
||||
marker.mark(words, {
|
||||
exclude: mark_exclude
|
||||
});
|
||||
|
||||
var markers = document.querySelectorAll("mark");
|
||||
function hide() {
|
||||
for (var i = 0; i < markers.length; i++) {
|
||||
markers[i].classList.add("fade-out");
|
||||
window.setTimeout(function(e) { marker.unmark(); }, 300);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < markers.length; i++) {
|
||||
markers[i].addEventListener('click', hide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eventhandler for keyevents on `document`
|
||||
function globalKeyHandler(e) {
|
||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea') { return; }
|
||||
|
||||
if (e.keyCode === ESCAPE_KEYCODE) {
|
||||
e.preventDefault();
|
||||
searchbar.classList.remove("active");
|
||||
setSearchUrlParameters("",
|
||||
(searchbar.value.trim() !== "") ? "push" : "replace");
|
||||
if (hasFocus()) {
|
||||
unfocusSearchbar();
|
||||
}
|
||||
showSearch(false);
|
||||
marker.unmark();
|
||||
} else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) {
|
||||
e.preventDefault();
|
||||
showSearch(true);
|
||||
window.scrollTo(0, 0);
|
||||
searchbar.select();
|
||||
} else if (hasFocus() && e.keyCode === DOWN_KEYCODE) {
|
||||
e.preventDefault();
|
||||
unfocusSearchbar();
|
||||
searchresults.firstElementChild.classList.add("focus");
|
||||
} else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE
|
||||
|| e.keyCode === UP_KEYCODE
|
||||
|| e.keyCode === SELECT_KEYCODE)) {
|
||||
// not `:focus` because browser does annoying scrolling
|
||||
var focused = searchresults.querySelector("li.focus");
|
||||
if (!focused) return;
|
||||
e.preventDefault();
|
||||
if (e.keyCode === DOWN_KEYCODE) {
|
||||
var next = focused.nextElementSibling;
|
||||
if (next) {
|
||||
focused.classList.remove("focus");
|
||||
next.classList.add("focus");
|
||||
}
|
||||
} else if (e.keyCode === UP_KEYCODE) {
|
||||
focused.classList.remove("focus");
|
||||
var prev = focused.previousElementSibling;
|
||||
if (prev) {
|
||||
prev.classList.add("focus");
|
||||
} else {
|
||||
searchbar.select();
|
||||
}
|
||||
} else { // SELECT_KEYCODE
|
||||
window.location.assign(focused.querySelector('a'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showSearch(yes) {
|
||||
if (yes) {
|
||||
search_wrap.classList.remove('hidden');
|
||||
searchicon.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
search_wrap.classList.add('hidden');
|
||||
searchicon.setAttribute('aria-expanded', 'false');
|
||||
var results = searchresults.children;
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
results[i].classList.remove("focus");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showResults(yes) {
|
||||
if (yes) {
|
||||
searchresults_outer.classList.remove('hidden');
|
||||
} else {
|
||||
searchresults_outer.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// Eventhandler for search icon
|
||||
function searchIconClickHandler() {
|
||||
if (search_wrap.classList.contains('hidden')) {
|
||||
showSearch(true);
|
||||
window.scrollTo(0, 0);
|
||||
searchbar.select();
|
||||
} else {
|
||||
showSearch(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Eventhandler for keyevents while the searchbar is focused
|
||||
function searchbarKeyUpHandler() {
|
||||
var searchterm = searchbar.value.trim();
|
||||
if (searchterm != "") {
|
||||
searchbar.classList.add("active");
|
||||
doSearch(searchterm);
|
||||
} else {
|
||||
searchbar.classList.remove("active");
|
||||
showResults(false);
|
||||
removeChildren(searchresults);
|
||||
}
|
||||
|
||||
setSearchUrlParameters(searchterm, "push_if_new_search_else_replace");
|
||||
|
||||
// Remove marks
|
||||
marker.unmark();
|
||||
}
|
||||
|
||||
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor .
|
||||
// `action` can be one of "push", "replace", "push_if_new_search_else_replace"
|
||||
// and replaces or pushes a new browser history item.
|
||||
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
|
||||
function setSearchUrlParameters(searchterm, action) {
|
||||
var url = parseURL(window.location.href);
|
||||
var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM);
|
||||
if (searchterm != "" || action == "push_if_new_search_else_replace") {
|
||||
url.params[URL_SEARCH_PARAM] = searchterm;
|
||||
delete url.params[URL_MARK_PARAM];
|
||||
url.hash = "";
|
||||
} else {
|
||||
delete url.params[URL_SEARCH_PARAM];
|
||||
}
|
||||
// A new search will also add a new history item, so the user can go back
|
||||
// to the page prior to searching. A updated search term will only replace
|
||||
// the url.
|
||||
if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) {
|
||||
history.pushState({}, document.title, renderURL(url));
|
||||
} else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) {
|
||||
history.replaceState({}, document.title, renderURL(url));
|
||||
}
|
||||
}
|
||||
|
||||
function doSearch(searchterm) {
|
||||
|
||||
// Don't search the same twice
|
||||
if (current_searchterm == searchterm) { return; }
|
||||
else { current_searchterm = searchterm; }
|
||||
|
||||
if (searchindex == null) { return; }
|
||||
|
||||
// Do the actual search
|
||||
var results = searchindex.search(searchterm, search_options);
|
||||
var resultcount = Math.min(results.length, results_options.limit_results);
|
||||
|
||||
// Display search metrics
|
||||
searchresults_header.innerText = formatSearchMetric(resultcount, searchterm);
|
||||
|
||||
// Clear and insert results
|
||||
var searchterms = searchterm.split(' ');
|
||||
removeChildren(searchresults);
|
||||
for(var i = 0; i < resultcount ; i++){
|
||||
var resultElem = document.createElement('li');
|
||||
resultElem.innerHTML = formatSearchResult(results[i], searchterms);
|
||||
searchresults.appendChild(resultElem);
|
||||
}
|
||||
|
||||
// Display results
|
||||
showResults(true);
|
||||
}
|
||||
|
||||
fetch(path_to_root + 'searchindex.json')
|
||||
.then(response => response.json())
|
||||
.then(json => init(json))
|
||||
.catch(error => { // Try to load searchindex.js if fetch failed
|
||||
var script = document.createElement('script');
|
||||
script.src = path_to_root + 'searchindex.js';
|
||||
script.onload = () => init(window.search);
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
|
||||
// Exported functions
|
||||
search.hasFocus = hasFocus;
|
||||
})(window.search);
|
||||
1
book/searchindex.js
Normal file
1
book/searchindex.js
Normal file
File diff suppressed because one or more lines are too long
1
book/searchindex.json
Normal file
1
book/searchindex.json
Normal file
File diff suppressed because one or more lines are too long
7
book/theme-dawn.js
Normal file
7
book/theme-dawn.js
Normal file
@@ -0,0 +1,7 @@
|
||||
ace.define("ace/theme/dawn",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-dawn",t.cssText=".ace-dawn .ace_gutter {background: #ebebeb;color: #333}.ace-dawn .ace_print-margin {width: 1px;background: #e8e8e8}.ace-dawn {background-color: #F9F9F9;color: #080808}.ace-dawn .ace_cursor {color: #000000}.ace-dawn .ace_marker-layer .ace_selection {background: rgba(39, 95, 255, 0.30)}.ace-dawn.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #F9F9F9;}.ace-dawn .ace_marker-layer .ace_step {background: rgb(255, 255, 0)}.ace-dawn .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(75, 75, 126, 0.50)}.ace-dawn .ace_marker-layer .ace_active-line {background: rgba(36, 99, 180, 0.12)}.ace-dawn .ace_gutter-active-line {background-color : #dcdcdc}.ace-dawn .ace_marker-layer .ace_selected-word {border: 1px solid rgba(39, 95, 255, 0.30)}.ace-dawn .ace_invisible {color: rgba(75, 75, 126, 0.50)}.ace-dawn .ace_keyword,.ace-dawn .ace_meta {color: #794938}.ace-dawn .ace_constant,.ace-dawn .ace_constant.ace_character,.ace-dawn .ace_constant.ace_character.ace_escape,.ace-dawn .ace_constant.ace_other {color: #811F24}.ace-dawn .ace_invalid.ace_illegal {text-decoration: underline;font-style: italic;color: #F8F8F8;background-color: #B52A1D}.ace-dawn .ace_invalid.ace_deprecated {text-decoration: underline;font-style: italic;color: #B52A1D}.ace-dawn .ace_support {color: #691C97}.ace-dawn .ace_support.ace_constant {color: #B4371F}.ace-dawn .ace_fold {background-color: #794938;border-color: #080808}.ace-dawn .ace_list,.ace-dawn .ace_markup.ace_list,.ace-dawn .ace_support.ace_function {color: #693A17}.ace-dawn .ace_storage {font-style: italic;color: #A71D5D}.ace-dawn .ace_string {color: #0B6125}.ace-dawn .ace_string.ace_regexp {color: #CF5628}.ace-dawn .ace_comment {font-style: italic;color: #5A525F}.ace-dawn .ace_heading,.ace-dawn .ace_markup.ace_heading {color: #19356D}.ace-dawn .ace_variable {color: #234A97}.ace-dawn .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYLh/5+x/AAizA4hxNNsZAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}); (function() {
|
||||
ace.require(["ace/theme/dawn"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
7
book/theme-tomorrow_night.js
Normal file
7
book/theme-tomorrow_night.js
Normal file
@@ -0,0 +1,7 @@
|
||||
ace.define("ace/theme/tomorrow_night",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-tomorrow-night",t.cssText=".ace-tomorrow-night .ace_gutter {background: #25282c;color: #C5C8C6}.ace-tomorrow-night .ace_print-margin {width: 1px;background: #25282c}.ace-tomorrow-night {background-color: #1D1F21;color: #C5C8C6}.ace-tomorrow-night .ace_cursor {color: #AEAFAD}.ace-tomorrow-night .ace_marker-layer .ace_selection {background: #373B41}.ace-tomorrow-night.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #1D1F21;}.ace-tomorrow-night .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-tomorrow-night .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #4B4E55}.ace-tomorrow-night .ace_marker-layer .ace_active-line {background: #282A2E}.ace-tomorrow-night .ace_gutter-active-line {background-color: #282A2E}.ace-tomorrow-night .ace_marker-layer .ace_selected-word {border: 1px solid #373B41}.ace-tomorrow-night .ace_invisible {color: #4B4E55}.ace-tomorrow-night .ace_keyword,.ace-tomorrow-night .ace_meta,.ace-tomorrow-night .ace_storage,.ace-tomorrow-night .ace_storage.ace_type,.ace-tomorrow-night .ace_support.ace_type {color: #B294BB}.ace-tomorrow-night .ace_keyword.ace_operator {color: #8ABEB7}.ace-tomorrow-night .ace_constant.ace_character,.ace-tomorrow-night .ace_constant.ace_language,.ace-tomorrow-night .ace_constant.ace_numeric,.ace-tomorrow-night .ace_keyword.ace_other.ace_unit,.ace-tomorrow-night .ace_support.ace_constant,.ace-tomorrow-night .ace_variable.ace_parameter {color: #DE935F}.ace-tomorrow-night .ace_constant.ace_other {color: #CED1CF}.ace-tomorrow-night .ace_invalid {color: #CED2CF;background-color: #DF5F5F}.ace-tomorrow-night .ace_invalid.ace_deprecated {color: #CED2CF;background-color: #B798BF}.ace-tomorrow-night .ace_fold {background-color: #81A2BE;border-color: #C5C8C6}.ace-tomorrow-night .ace_entity.ace_name.ace_function,.ace-tomorrow-night .ace_support.ace_function,.ace-tomorrow-night .ace_variable {color: #81A2BE}.ace-tomorrow-night .ace_support.ace_class,.ace-tomorrow-night .ace_support.ace_type {color: #F0C674}.ace-tomorrow-night .ace_heading,.ace-tomorrow-night .ace_markup.ace_heading,.ace-tomorrow-night .ace_string {color: #B5BD68}.ace-tomorrow-night .ace_entity.ace_name.ace_tag,.ace-tomorrow-night .ace_entity.ace_other.ace_attribute-name,.ace-tomorrow-night .ace_meta.ace_tag,.ace-tomorrow-night .ace_string.ace_regexp,.ace-tomorrow-night .ace_variable {color: #CC6666}.ace-tomorrow-night .ace_comment {color: #969896}.ace-tomorrow-night .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHB3d/8PAAOIAdULw8qMAAAAAElFTkSuQmCC) right repeat-y}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}); (function() {
|
||||
ace.require(["ace/theme/tomorrow_night"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -4,8 +4,8 @@ Before we go into the details about Futures in Rust, let's take a quick look
|
||||
at the alternatives for handling concurrent programming in general and some
|
||||
pros and cons for each of them.
|
||||
|
||||
While we do that we'll get some information on concurrency which will make it
|
||||
easier for us when we dive in to Futures specifically.
|
||||
While we do that we'll also explain some aspects when it comes to concurrency which
|
||||
will make it easier for us when we dive in to Futures specifically.
|
||||
|
||||
> For fun, I've added a small snipped of runnable code with most of the examples.
|
||||
> If you're like me, things get way more interesting then and maybe you'll se some
|
||||
@@ -68,7 +68,7 @@ fn main() {
|
||||
OS threads sure has some pretty big advantages. So why all this talk about
|
||||
"async" and concurrency in the first place?
|
||||
|
||||
First of all. For computers to be [_efficient_](https://en.wikipedia.org/wiki/Efficiency) it needs to multitask. Once you
|
||||
First of all. For computers to be [_efficient_](https://en.wikipedia.org/wiki/Efficiency) they needs to multitask. Once you
|
||||
start to look under the covers (like [how an operating system works](https://os.phil-opp.com/async-await/))
|
||||
you'll see concurrency everywhere. It's very fundamental in everything we do.
|
||||
|
||||
@@ -79,10 +79,9 @@ Webservers is all about I/O and handling small tasks
|
||||
threads as of today because of the memory they require and the overhead involved
|
||||
when creating new threads.
|
||||
|
||||
This gets even more relevant when the load is variable
|
||||
which means the current number of tasks a program has at any point in time is
|
||||
unpredictable. That's why you'll see so many async web frameworks and database
|
||||
drivers today.
|
||||
This gets even more problematic when the load is variable which means the current number of tasks a
|
||||
program has at any point in time is unpredictable. That's why you'll see so many async web
|
||||
frameworks and database drivers today.
|
||||
|
||||
However, for a huge number of problems, the standard OS threads will often be the
|
||||
right solution. So, just think twice about your problem before you reach for an
|
||||
@@ -105,15 +104,16 @@ 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 for `async`, `await`, `Futures` or `Pin`.
|
||||
|
||||
The typical flow will be like this:
|
||||
**The typical flow looks like this:**
|
||||
|
||||
1. Run som non-blocking code
|
||||
1. Run some non-blocking code
|
||||
2. Make a blocking call to some external resource
|
||||
3. CPU jumps to the "main" thread which schedules a different thread to run and
|
||||
"jumps" to that stack
|
||||
4. Run some non-blocking code on the new thread until a new blocking call or the
|
||||
task is finished
|
||||
5. "jumps" back to the "main" thread, schedule a new thread to run and jump to that
|
||||
5. "jumps" back to the "main" thread, schedule a new thread which is ready to make
|
||||
progress and jump to that.
|
||||
|
||||
These "jumps" are know as **context switches**. Your OS is doing it many times each
|
||||
second as you read this.
|
||||
@@ -374,10 +374,11 @@ in life, close your eyes now and scroll down for 2-3 seconds. You'll find a link
|
||||
there that takes you to safety.
|
||||
|
||||
The whole idea behind a callback based approach is to save a pointer to a set of
|
||||
instructions we want to run later. We can save that pointer on the stack before
|
||||
we yield control to the runtime, or in some sort of collection as we do below.
|
||||
instructions we want to run later together with whatever state is needed. In rust this
|
||||
would be a `closure`. In the example below, we save this information in a `HashMap`
|
||||
but it's not the only option.
|
||||
|
||||
The basic idea of not involving threads as a primary way to achieve concurrency
|
||||
The basic idea of _not_ involving threads as a primary way to achieve concurrency
|
||||
is the common denominator for the rest of the approaches. Including the one
|
||||
Rust uses today which we'll soon get to.
|
||||
|
||||
@@ -385,7 +386,7 @@ Rust uses today which we'll soon get to.
|
||||
|
||||
- Easy to implement in most languages
|
||||
- No context switching
|
||||
- Low memory overhead (in most cases)
|
||||
- Relatively low memory overhead (in most cases)
|
||||
|
||||
**Drawbacks:**
|
||||
|
||||
@@ -472,11 +473,11 @@ impl Runtime {
|
||||
|
||||
We're keeping this super simple, and you might wonder what's the difference
|
||||
between this approach and the one using OS threads an passing in the callbacks
|
||||
to the OS threads directly.
|
||||
to the OS threads directly.
|
||||
|
||||
The difference is that the callbacks are run on the
|
||||
same thread using this example. The OS threads we create are basically just used
|
||||
as timers.
|
||||
as timers but could represent any kind of resource that we'll have to wait for.
|
||||
|
||||
## From callbacks to promises
|
||||
|
||||
@@ -552,7 +553,7 @@ Now this is also where the similarities with Rusts Futures stop. The reason we
|
||||
go through all this is to get an introduction and get into the right mindset for
|
||||
exploring Rusts Futures.
|
||||
|
||||
> To avoid confusion later on: There is one difference you should know. Javascript
|
||||
> To avoid confusion later on: There's one difference you should know. Javascript
|
||||
> promises are _eagerly_ evaluated. That means that once it's created, it starts
|
||||
> running a task. Rusts Futures on the other hand is _lazily_ evaluated. They
|
||||
> need to be polled once before they do any work.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Futures Explained in 200 Lines of Rust
|
||||
|
||||
This book aims to explain `Futures` in Rust using an example driven approach,
|
||||
exploring why they're designed the way they are, the alternatives and how
|
||||
they work.
|
||||
exploring why they're designed the way they are, and how they work. We'll also
|
||||
take a look at some of the alternatives we have when dealing with concurrency
|
||||
in programming.
|
||||
|
||||
Going into the level of detail I do in this book is not needed to use futures
|
||||
or async/await in Rust. It's for the curious out there that want to know _how_
|
||||
@@ -16,9 +17,8 @@ simple runtime in this book introducing some concepts but it's enough to get
|
||||
started.
|
||||
|
||||
[Stjepan Glavina](https://github.com/stjepang) has made an excellent series of
|
||||
articles about async runtimes and executors, and if the rumors are right he's
|
||||
even working on a new async runtime that should be easy enough to use as
|
||||
learning material.
|
||||
articles about async runtimes and executors, and if the rumors are right there
|
||||
is more to come from him in the near future.
|
||||
|
||||
The way you should go about it is to read this book first, then continue
|
||||
reading the [articles from stejpang](https://stjepang.github.io/) to learn more
|
||||
@@ -39,6 +39,8 @@ I hope you enjoy the ride.
|
||||
> [the repository for the book itself here][book_repo]. The final example which
|
||||
> you can clone, fork or copy [can be found here][example_repo]. Any suggestions
|
||||
> or improvements can be filed as a PR or in the issue tracker for the book.
|
||||
>
|
||||
> As always, all kinds of feedback is welcome.
|
||||
|
||||
## Reader exercises and further reading
|
||||
|
||||
|
||||
Reference in New Issue
Block a user