merged with latest changes and made some additional corrections

This commit is contained in:
Carl Fredrik Samson
2020-04-10 20:39:35 +02:00
19 changed files with 488 additions and 487 deletions

View File

@@ -213,11 +213,11 @@ fn main() {
<p>First, for computers to be <a href="https://en.wikipedia.org/wiki/Efficiency"><em>efficient</em></a> they need 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>Second, we have the web. </p>
<p>Secondly, we have the web.</p>
<p>Web servers are all about I/O and handling small tasks
(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>
when creating new threads.</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>
@@ -235,7 +235,7 @@ task(thread) to another by doing a &quot;context switch&quot;.</p>
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>
need for <code>async</code>, <code>await</code>, <code>Future</code> or <code>Pin</code>.</p>
<p><strong>The typical flow looks like this:</strong></p>
<ol>
<li>Run some non-blocking code.</li>
@@ -276,26 +276,26 @@ in that book. The code below is wildly unsafe and it's just to show a real examp
It's not in any way meant to showcase &quot;best practice&quot;. Just so we're on
the same page.</p>
</blockquote>
<p><em><strong>Press the expand icon in the top right corner to show the example code.</strong></em> </p>
<p><em><strong>Press the expand icon in the top right corner to show the example code.</strong></em></p>
<pre><pre class="playpen"><code class="language-rust edition2018"># #![feature(asm, naked_functions)]
# use std::ptr;
#
#
# const DEFAULT_STACK_SIZE: usize = 1024 * 1024 * 2;
# const MAX_THREADS: usize = 4;
# static mut RUNTIME: usize = 0;
#
#
# pub struct Runtime {
# threads: Vec&lt;Thread&gt;,
# current: usize,
# }
#
#
# #[derive(PartialEq, Eq, Debug)]
# enum State {
# Available,
# Running,
# Ready,
# }
#
#
# struct Thread {
# id: usize,
# stack: Vec&lt;u8&gt;,
@@ -303,7 +303,7 @@ the same page.</p>
# state: State,
# task: Option&lt;Box&lt;dyn Fn()&gt;&gt;,
# }
#
#
# #[derive(Debug, Default)]
# #[repr(C)]
# struct ThreadContext {
@@ -316,7 +316,7 @@ the same page.</p>
# rbp: u64,
# thread_ptr: u64,
# }
#
#
# impl Thread {
# fn new(id: usize) -&gt; Self {
# Thread {
@@ -328,7 +328,7 @@ the same page.</p>
# }
# }
# }
#
#
# impl Runtime {
# pub fn new() -&gt; Self {
# let base_thread = Thread {
@@ -338,37 +338,37 @@ the same page.</p>
# state: State::Running,
# task: None,
# };
#
#
# let mut threads = vec![base_thread];
# threads[0].ctx.thread_ptr = &amp;threads[0] as *const Thread as u64;
# let mut available_threads: Vec&lt;Thread&gt; = (1..MAX_THREADS).map(|i| Thread::new(i)).collect();
# threads.append(&amp;mut available_threads);
#
#
# Runtime {
# threads,
# current: 0,
# }
# }
#
#
# pub fn init(&amp;self) {
# unsafe {
# let r_ptr: *const Runtime = self;
# RUNTIME = r_ptr as usize;
# }
# }
#
#
# pub fn run(&amp;mut self) -&gt; ! {
# while self.t_yield() {}
# std::process::exit(0);
# }
#
#
# fn t_return(&amp;mut self) {
# if self.current != 0 {
# self.threads[self.current].state = State::Available;
# self.t_yield();
# }
# }
#
#
# fn t_yield(&amp;mut self) -&gt; bool {
# let mut pos = self.current;
# while self.threads[pos].state != State::Ready {
@@ -380,21 +380,21 @@ the same page.</p>
# return false;
# }
# }
#
#
# if self.threads[self.current].state != State::Available {
# self.threads[self.current].state = State::Ready;
# }
#
#
# self.threads[pos].state = State::Running;
# let old_pos = self.current;
# self.current = pos;
#
#
# unsafe {
# switch(&amp;mut self.threads[old_pos].ctx, &amp;self.threads[pos].ctx);
# }
# true
# }
#
#
# pub fn spawn&lt;F: Fn() + 'static&gt;(f: F){
# unsafe {
# let rt_ptr = RUNTIME as *mut Runtime;
@@ -403,7 +403,7 @@ the same page.</p>
# .iter_mut()
# .find(|t| t.state == State::Available)
# .expect(&quot;no available thread.&quot;);
#
#
# let size = available.stack.len();
# let s_ptr = available.stack.as_mut_ptr();
# available.task = Some(Box::new(f));
@@ -415,14 +415,14 @@ the same page.</p>
# }
# }
# }
#
#
# fn call(thread: u64) {
# let thread = unsafe { &amp;*(thread as *const Thread) };
# if let Some(f) = &amp;thread.task {
# f();
# }
# }
#
#
# #[naked]
# fn guard() {
# unsafe {
@@ -432,14 +432,14 @@ the same page.</p>
# rt.t_return();
# };
# }
#
#
# pub fn yield_thread() {
# unsafe {
# let rt_ptr = RUNTIME as *mut Runtime;
# (*rt_ptr).t_yield();
# };
# }
#
#
# #[naked]
# #[inline(never)]
# unsafe fn switch(old: *mut ThreadContext, new: *const ThreadContext) {
@@ -451,7 +451,7 @@ the same page.</p>
# mov %r12, 0x20($0)
# mov %rbx, 0x28($0)
# mov %rbp, 0x30($0)
#
#
# mov 0x00($1), %rsp
# mov 0x08($1), %r15
# mov 0x10($1), %r14
@@ -493,7 +493,7 @@ difficult to understand. If I hadn't written it myself I would probably feel
the same. You can always go back and read the book which explains it later.</p>
<h2><a class="header" href="#callback-based-approaches" id="callback-based-approaches">Callback based approaches</a></h2>
<p>You probably already know what we're going to talk about in the next paragraphs
from JavaScript which I assume most know. </p>
from JavaScript which I assume most know.</p>
<blockquote>
<p>If your exposure to JavaScript callbacks has given you any sorts of PTSD earlier
in life, close your eyes now and scroll down for 2-3 seconds. You'll find a link
@@ -600,8 +600,8 @@ same thread using this example. The OS threads we create are basically just used
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
deferred computations are often used interchangeably. </p>
<p>Well, we're getting there. You see Promises, Futures and other names for
deferred computations are often used interchangeably.</p>
<p>There are formal differences between them, but we won't cover those
here. It's worth explaining <code>promises</code> a bit since they're widely known due to
their use in JavaScript. Promises also have a lot in common with Rust's Futures.</p>
@@ -629,8 +629,8 @@ timer(200)
.then(() =&gt; console.log(&quot;I'm the last one&quot;));
</code></pre>
<p>The change is even more substantial under the hood. You see, promises return
a state machine which can be in one of three states: <code>pending</code>, <code>fulfilled</code> or
<code>rejected</code>. </p>
a state machine which can be in one of three states: <code>pending</code>, <code>fulfilled</code> or
<code>rejected</code>.</p>
<p>When we call <code>timer(200)</code> in the sample above, we get back a promise in the state <code>pending</code>.</p>
<p>Since promises are re-written as state machines, they also enable an even better
syntax which allows us to write our last example like this:</p>
@@ -658,9 +658,10 @@ running a task. Rust's Futures on the other hand are <em>lazily</em> evaluated.
need to be polled once before they do any work.</p>
</blockquote>
<br />
<div style="text-align: center; padding-top: 2em;">
<div style="text-align: center; padding-top: 2em;">
<a href="/books-futures-explained/1_futures_in_rust.html" style="background: red; color: white; padding:2em 2em 2em 2em; font-size: 1.2em;"><strong>PANIC BUTTON (next chapter)</strong></a>
</div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">