Concurrency

with

JavaScript

Downtown ReactJS Meetup - 2018/08/28

Layout

  • Concurrency vs Parallelism

  • Evented Model / Event Loop

  • V8 / DOM

  • React Reconciliation / Redux-Saga Async Effects

Currency vs Parallelism

  • Asynchronous vs Synchronous
  • Blocking vs Non-Blocking
  • Single Process vs Cooperative Multitasking
  • Preemptive vs Non-Preemptive
  • Simultaneous Multi Threading (SMT - hyper threading)

OS vs Userland

What is Concurrency?

two or more tasks can start, run, and complete in overlapping time periods. It doesn't rule out that the tasks can be both be running at the same instant. For example, multitasking on a single- vs multi-core machine.

... a property of a program or system

What is Concurrency?

What is Parallelism?

tasks literally run at the same time e.g., on a multicore processor.

parallelism as the run-time behaviour of executing multiple tasks at the same time

What is Parallelism?

Multi-

Multi-tasking

    -is a Process

    -top-level execution container

    -have their own memory space

    -communicate with other processes via IPC

    -sandbox / safety

 

Multi-threading

    -runs inside a process

    -share same memory

    -need to manage sync

OS vs Userland

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}
// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x

Multi-Threading

race condition

Trade Offs

  • The user writes async code
  • The OS manages threads
  • The user writes sync code
  • The user manages threads

Real-world

  • Firefox
    • old: browser ran on a single process
    • new: split UI vs Content (Electrolysis)
  • Chrome
    • Tabs run in their own process
    • Rendering, plug-ins

 

Detour

Sync - Async

Single - Multi Threaded

Sync Async
Single Threaded Sequential Interleaved
Multi-Threaded Parallel Interleaved-Parallel

Detour

Single Theaded - Sync

Detour

Multi-Theaded - Sync

Detour

Single Theaded - Async

Detour

Multi-Theaded - Async

JavaScript is

Single Threaded

Race conditions cannot happen

"Everything runs in parallel except your code"

JavaScript is

Synchronous

one operation is executed at a time

write code to make it behave asynchronous

a thread is much lighter than a process, a function call is much lighter than a thread. Call functions instead of creating threads

 

functions run one at a time, never two in parallel.

in a single process, only one scope of code is running at a time.

 

the OS Scheduler does not come and pause this function and switch to another one, unless it pauses the process to give time to another process, not another thread in our process.

 

a process can handle tens of thousands of requests at a time as long as the system has enough resources (RAM, Network, etc.).

 

How those functions run is THE KEY DIFFERENCE.

// Example 1 - Synchronous (blocks) - Ruby
response = Faraday.get 'http://www.google.com'
puts response
puts 'Done!'


// Example 2 - Asynchronous (doesn't block) 
request('http://www.google.com', function(error, response, body) {
  console.log(body);
});

console.log('Done!');
Promise.all([apiRequest(...), fs.readFileAsync(...), readTemperature(...)])
    .then(function(results) {
        // all results in the results array here
        // processing can continue using the results of all three async operations
    }, function(err) {
        // an error occurred, process the error here
    }
); 

JavaScript's Concurrency model is based on the

Event Loop

Event-Driven Model

A programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads.

In an event-driven application, there is generally a main loop that listens for events, and then triggers a callback function when one of those events is detected

Event Loop

Event Loop Phases

Timers

executes callbacks scheduled by setTimeout() and setInterval().

const fs = require('fs');

function someAsyncOperation(callback) {
  // Assume this takes 95ms to complete
  fs.readFile('/path/to/file', callback);
}

const timeoutScheduled = Date.now();

setTimeout(() => {
  const delay = Date.now() - timeoutScheduled;

  console.log(`${delay}ms have passed since I was scheduled`);
}, 100);


// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() => {
  const startCallback = Date.now();

  // do something that will take 10ms...
  while (Date.now() - startCallback < 10) {
    // do nothing
  }
});

Pending Callbacks

executes I/O callbacks deferred to the next loop iteration.

Idle, Prepare

used internally

Poll

  1. Calculating how long it should block and poll for I/O, then
  2. Processing events in the poll queue.

Check

setImmediate() callbacks are invoked here

Close Callbacks

some close callbacks, e.g. socket.on('close', ...).

Event Loop

JavaScript Event Loop

Single Threaded

Synchronous Execution

Asynchronously Written

Promises

async function asyncFun () {
  var value = await Promise
    .resolve(1)
    .then(x => x * 3)
    .then(x => x + 5)
    .then(x => x / 2);
  return value;
}
asyncFun().then(x => console.log(`x: ${x}`));
// <- 'x: 4'
// Sequential
await someCall();
await anotherCall();


// Async push -- Sync wait
var taskA = someCall();
var taskB = someOtherCall();
await taskA;
await taskB;



// Parallel
Promise.all([taskA, taskB])

JavaScript Event Loop

Event Loop

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

Event Loop

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});
Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

DOM

DOM

document.

body

getElementById

getElementsByClassName

addEventListener

etc

html is text. DOM is in-memory representation of html text

DOM

DOM is tree-structured

DOM trees are easy to traverse

ENTER THE SPA

need to manipulate the tree A LOT!!

DOM

  • find node(s) of interest
    • page loaded? element available?
  • update node(s) if necessary
    • when to update? data incoming?
  • repeat

OS vs Userland

Virtual DOM*

  • simplified copy of the DOM (JS objects)
  • browser-independent
  • can be optimized - diffing, batch updates

*Facebook did not invent this

Cheng Lou - On the Spectrum of Abstraction at react-europe 2016

https://www.youtube.com/watch?v=mVVNJKv9esE

ReactJS

It is a key goal for React that the amount of the user code that executes before yielding back into React is minimal.

 

This ensures that React retains the capability to schedule and split work in chunks according to what it knows about the UI.

OS vs Usercode

ReactJS

consequence:

    -userland functions are not called directly

    -react calls your function

    -"pull" based

      A push-based approach requires the programmer to decide how to schedule work.

nothing new. implementation of a very good idea

ReactJS vDOM

React Elements -- createElement

    -atoms of the vDom

    -immutability

    -stateless

 

React Components -- createClass

    -stateful

    -don't have access to vDom -> needs to be converted to React Elements

ReactJS

class Hello extends React.Component {
  // add state here
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

ReactDOM.render(
  React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

ReactJS Reconciliation

  1. Two elements of different types will produce different trees
  2. The developer can hint at which child elements may be stable across different renders with a key prop.

elements of different type

    -roots differ

elements of same type

    -attributes differ

    -lifecycle hooks

recursing on children

Redux-Saga

The mental model of a saga is like a separate thread in your application that's solely responsible for side effects.

asynchronous things like data fetching and impure things like accessing the browser cache

it is middleware, which means that the thread can be started, paused and cancelled from the main application with normal redux actions, it has access to the full redux application state and it can dispatch redux actions as well.

Redux-Saga

Similar to Communication Sequential Processes (CSP)

    -supports channels, async

 

Similar to Actor Model

    -DOES NOT: parent/child, sender/receiver communication, retry/recovery patterns

    -DOES: react to changes

 

Similar to Coroutines

    -DOES NOT: have it's own stack

    -DOES: pass control to another suspended generator

OS vs Userland

Web Workers

  • Dedicated Worker
  • Shared Worker

isolated thread

    -code lives in its own file

    -some APIs are not accessible (i.e. DOM)

postMessage

    -communicates with the Main Thread

Spawn other workers (sub-workers)

Web Workers

  • Dedicated Worker
  • Shared Worker

isolated thread

    -code lives in its own file

    -some APIs are not accessible (i.e. DOM)

postMessage

    -communicates with the Main Thread

Spawn other workers (sub-workers)

main

worker

Multi-Theaded - Async

The goal is to move away from this

Async Rendering

Part 2

  • Quick Recap
  • Web Workers
  • Fiber
  • Async Rendering
  • Sagas

You're only as good as the problems you solve

Write code for other humans

    - NOT for IDEs

    - NOT for Version Control

    - NOT for Machines

 

How you write has a direct impact on how your application will run

Independent of technology your application is only as good as the developers skills set

Always be learning

Resources:

Resources:

Made with Slides.com