Files
books-futures-explained/book/1_background_information.html
Carl Fredrik Samson 70c4020059 continued version 2
2020-02-24 23:25:48 +01:00

375 lines
20 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Some background information - Futures Explained in 200 Lines of Rust</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="This book aims to explain Futures in Rust using an example driven approach.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="light">
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
document.body.className = theme;
document.querySelector('html').className = theme + ' js';
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<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_waker_context.html"><strong aria-hidden="true">2.</strong> Waker and Context</a></li><li><a href="3_generators_pin.html"><strong aria-hidden="true">3.</strong> Generators</a></li><li><a href="4_pin.html"><strong aria-hidden="true">4.</strong> Pin</a></li><li><a href="6_future_example.html"><strong aria-hidden="true">5.</strong> Futures - our main example</a></li><li><a href="8_finished_example.html"><strong aria-hidden="true">6.</strong> Finished example (editable)</a></li><li class="affix"><a href="conclusion.html">Conclusion and exercises</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Futures Explained in 200 Lines of Rust</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/cfsamson/books-futures-explained" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1><a class="header" href="#some-background-information" id="some-background-information">Some background information</a></h1>
<blockquote>
<p><strong>Relevant for:</strong></p>
<ul>
<li>High level introduction to concurrency in Rust</li>
<li>Knowing what Rust provides and not when working with async code</li>
<li>Understanding why we need runtimes </li>
<li>Getting pointers to further reading on concurrency in general</li>
</ul>
</blockquote>
<p>Before we start implementing our <code>Futures</code> , we'll go through some background
information that will help demystify some of the concepts we encounter.</p>
<p>Actually, after going through these concepts, implementing futures will seem
pretty simple. I promise.</p>
<h2><a class="header" href="#futures" id="futures">Futures</a></h2>
<p>So what is a future?</p>
<p>A future is a representation of some operation which will complete in the
future.</p>
<p>Async in Rust uses a <code>Poll</code> based approach, in which an asynchronous task will
have three phases.</p>
<ol>
<li><strong>The Poll phase.</strong> A Future is polled which result in the task progressing until
a point where it can no longer make progress. We often refer to the part of the
runtime which polls a Future as an executor.</li>
<li><strong>The Wait phase.</strong> An event source, most often referred to as a reactor,
registers that a Future is waiting for an event to happen and makes sure that it
will wake the Future when that event is ready.</li>
<li><strong>The Wake phase.</strong> The event happens and the Future is woken up. It's now up
to the executor which polled the Future in step 1 to schedule the future to be
polled again and make further progress until it completes or reaches a new point
where it can't make further progress and the cycle repeats.</li>
</ol>
<p>Now, when we talk about futures I find it useful to make a distinction between
<strong>non-leaf</strong> futures and <strong>leaf</strong> futures early on because in practice they're
pretty different from one another.</p>
<h3><a class="header" href="#leaf-futures" id="leaf-futures">Leaf futures</a></h3>
<p>Runtimes create <em>leaf futures</em> which represents a resource like a socket.</p>
<pre><code class="language-rust ignore noplaypen">// stream is a **leaf-future**
let mut stream = tokio::net::TcpStream::connect(&quot;127.0.0.1:3000&quot;);
</code></pre>
<p>Operations on these resources, like a <code>Read</code> on a socket, will be non-blocking
and return a future which we call a leaf future since it's the future which
we're actually waiting on.</p>
<p>It's unlikely that you'll implement a leaf future yourself unless you're writing
a runtime, but we'll go through how they're constructed in this book as well.</p>
<p>It's also unlikely that you'll pass a leaf-future to a runtime and run it to
completion alone as you'll understand by reading the next paragraph.</p>
<h3><a class="header" href="#non-leaf-futures" id="non-leaf-futures">Non-leaf-futures</a></h3>
<p>Non-leaf-futures is the kind of futures we as <em>users</em> of a runtime writes
ourselves using the <code>async</code> keyword to create a <strong>task</strong> which can be run on the
executor.</p>
<p>The bulk of an async program will consist of non-leaf-futures, which are a kind
of pause-able computation. This is an important distinction since these futures represents a <em>set of operations</em>. Often, such a task will <code>await</code> a leaf future
as one of many operations to complete the task.</p>
<pre><code class="language-rust ignore noplaypen">// Non-leaf-future
let non_leaf = async {
let mut stream = TcpStream::connect(&quot;127.0.0.1:3000&quot;).await.unwrap();// &lt;- yield
println!(&quot;connected!&quot;);
let result = stream.write(b&quot;hello world\n&quot;).await; // &lt;- yield
println!(&quot;message sent!&quot;);
...
};
</code></pre>
<p>The key to these tasks is that they're able to yield control to the runtime's
scheduler and then resume execution again where it left off at a later point.</p>
<p>In contrast to leaf futures, these kind of futures does not themselves represent
an I/O resource. When we poll these futures we either run some code or we yield
to the scheduler while waiting for some resource to signal us that it's ready so
we can resume where we left off.</p>
<h2><a class="header" href="#runtimes" id="runtimes">Runtimes</a></h2>
<p>Languages like C#, JavaScript, Java, GO and many others comes with a runtime
for handling concurrency. So if you come from one of those languages this will
seem a bit strange to you.</p>
<p>Rust is different from these languages in the sense that Rust doesn't come with
a runtime for handling concurrency, so you need to use a library which provide
this for you.</p>
<p>Quite a bit of complexity attributed to <code>Futures</code> are actually complexity rooted
in runtimes. Creating an efficient runtime is hard.</p>
<p>Learning how to use one correctly requires quite a bit of effort as well, but
you'll see that there are several similarities between these kind of runtimes so
learning one makes learning the next much easier.</p>
<p>The difference between Rust and other languages is that you have to make an
active choice when it comes to picking a runtime. Most often, in other languages
you'll just use the one provided for you.</p>
<p>An async runtime can be divided into two parts:</p>
<ol>
<li>The Executor</li>
<li>The Reactor</li>
</ol>
<p>When Rusts Futures were designed there was a desire to separate the job of
notifying a <code>Future</code> that it can do more work, and actually doing the work
on the <code>Future</code>.</p>
<p>You can think of the former as the reactor's job, and the latter as the
executors job. These two parts of a runtime interacts using the <code>Waker</code> type.</p>
<p>The two most popular runtimes for <code>Futures</code> as of writing this is:</p>
<ul>
<li><a href="https://github.com/async-rs/async-std">async-std</a></li>
<li><a href="https://github.com/tokio-rs/tokio">Tokio</a></li>
</ul>
<h3><a class="header" href="#what-rusts-standard-library-takes-care-of" id="what-rusts-standard-library-takes-care-of">What Rust's standard library takes care of</a></h3>
<ol>
<li>A common interface representing an operation which will be completed in the
future through the <code>Future</code> trait.</li>
<li>An ergonomic way of creating tasks which can be suspended and resumed through
the <code>async</code> and <code>await</code> keywords.</li>
<li>A defined interface wake up a suspended task through the <code>Waker</code> type.</li>
</ol>
<p>That's really what Rusts standard library does. As you see there is no definition
of non-blocking I/O, how these tasks are created or how they're run.</p>
<h2><a class="header" href="#bonus-section" id="bonus-section">Bonus section</a></h2>
<p>If you find the concepts of concurrency and async programming confusing in
general, I know where you're coming from and I have written some resources to
try to give a high level overview that will make it easier to learn Rusts
<code>Futures</code> afterwards:</p>
<ul>
<li><a href="https://cfsamson.github.io/book-exploring-async-basics/1_concurrent_vs_parallel.html">Async Basics - The difference between concurrency and parallelism</a></li>
<li><a href="https://cfsamson.github.io/book-exploring-async-basics/2_async_history.html">Async Basics - Async history</a></li>
<li><a href="https://cfsamson.github.io/book-exploring-async-basics/5_strategies_for_handling_io.html">Async Basics - Strategies for handling I/O</a></li>
<li><a href="https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html">Async Basics - Epoll, Kqueue and IOCP</a></li>
</ul>
<p>Learning these concepts by studying futures is making it much harder than
it needs to be, so go on and read these chapters if you feel a bit unsure. </p>
<p>I'll be right here when you're back.</p>
<p>However, if you feel that you have the basics covered, then let's get moving!</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="introduction.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="2_waker_context.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="introduction.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="2_waker_context.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script type="text/javascript">
var socket = new WebSocket("ws://localhost:3001");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload(true); // force reload from server (not from cache)
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<!-- Google Analytics Tag -->
<script type="text/javascript">
var localAddrs = ["localhost", "127.0.0.1", ""];
// make sure we don't activate google analytics if the developer is
// inspecting the book locally...
if (localAddrs.indexOf(document.location.hostname) === -1) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-157536992-1', 'auto');
ga('send', 'pageview');
}
</script>
<script src="ace.js" type="text/javascript" charset="utf-8"></script>
<script src="editor.js" type="text/javascript" charset="utf-8"></script>
<script src="mode-rust.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-dawn.js" type="text/javascript" charset="utf-8"></script>
<script src="theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>