Search code examples
javascriptparallel-processingmutable

How to run two setTimeout tasks in parallel?


I'm reading YDKJS and early on we are talking about the difference between Async, Parallel and Concurrent Code.

I have a simple Async example:

let output = 0;
const bar = (cb) => setTimeout(cb, Math.random() * 1000);
const foo = (cb) => setTimeout(cb, Math.random() * 1000);

bar( () => {
    output = 1;
});
foo( () => {
    output = 2
});
setTimeout(() => {
    // This Async code should have 2 different outputs
    output;
}, 2000);

The above code can have the 2 answers based on the Math.random timer and the mutable output:

However, I'd like to add a bit more complexity and convert foo and bar to run in parallel... I don't have much understanding on how I can achieve this:

Question: How can we update the code below, so that bar and foo are run in parallel and therefore, output has more than 2 possible outcomes?

Note: this is purely for learning purposes... I want to see the race conditions occure.

let inputA = 10;
let inputB = 11;

const bar = (cb) => setTimeout(cb, Math.random() * 1000);
const foo = (cb) => setTimeout(cb, Math.random() * 1000);


bar( () => {
    inputA++;
    inputB = inputB * inputA;
    inputA = inputA + 3;
});
foo( () => {
    inputB--;
    inputA = 8 + inputB;
    inputB =  inputA * 2;
});
setTimeout(() => {
    // This Parallel code should have more than 2 outputs;
    console.log(inputA, inputB);
}, 2000);

Solution

  • The race condition you're looking to invoke isn't possible in ordinary Javascript, luckily. Any time you have a synchronous function, once control flow is passed to that function, that function is absolutely guaranteed to run to the end (or throw) before any other Javascript in the environment runs.

    For example, given 1000 tasks which are scheduled by setTimeout to occur in the next 1-2 seconds (randomly), and you also invoke the following function after 1.5 seconds:

    const fn = () => {
      console.log('1');
      for (let i = 0; i < 1e8; i++) {
      }
      console.log('2');
    };
    

    Once fn starts, it will run all of its code (synchronously) before the next random function runs. So even if the random functions call console.log, it is still guaranteed that, in the above situation, 2 will be logged right after 1.

    So, in your original example, there are only 2 possibilities:

    • bar's callback runs first, and completely finishes, then foo's callback runs, and completely finishes. Or:
    • foo's callback runs first, and completely finishes, then bar's callback runs, and completely finishes.

    Nothing else is possible, even if the random timeouts land on exactly the same number. Control flow can only be in exactly one place in the code at any given time.