Как запустить две задачи setTimeout параллельно? - PullRequest
0 голосов
/ 13 апреля 2020

Я читаю YDK JS и в начале мы говорим о разнице между Asyn c, Параллельным и Параллельным Кодом.

У меня есть простой Asyn c пример:

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);

Приведенный выше код может иметь 2 ответа на основе таймера Math.random и изменяемого вывода:

Однако я хотел бы добавить немного больше сложности и преобразовать foo и bar для параллельной работы ... Я не очень понимаю, как мне этого добиться:

Вопрос: Как мы можем обновить приведенный ниже код, чтобы bar и foo выполняются параллельно, и, следовательно, выход имеет более 2 возможных результатов?

Примечание: это чисто для целей обучения ... Я хочу увидеть условия гонки.

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);

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Состояние гонки, которое вы хотите вызвать, в обычном случае Javascript, к счастью, невозможно. Каждый раз, когда у вас есть синхронная функция, когда поток управления передается этой функции, эта функция абсолютно гарантированно будет работать до конца (или сгенерирована) до запуска любого другого Javascript в среде.

Например, при задании 1000 задач, запланированных на setTimeout, в ближайшие 1-2 секунды (случайным образом), а также через 1,5 секунды вы также вызываете следующую функцию:

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

После запуска fn, он выполнит весь свой код (синхронно) до запуска следующей случайной функции. Таким образом, даже если случайные функции вызывают console.log, все равно гарантируется, что в вышеуказанной ситуации 2 будет зарегистрирован сразу после 1.

Итак, в вашем исходном примере есть только 2 возможности:

  • bar обратный вызов запускается сначала и полностью завершается, затем обратный вызов foo выполняется и полностью завершается. Или:
  • foo выполняется обратный вызов сначала и полностью завершается, затем bar выполняется обратный вызов и полностью завершается.

Ничего другого невозможно, даже если случайные таймауты приземляются на точно такое же число Поток управления может быть только в точно в одном месте в коде в любой момент времени.

0 голосов
/ 13 апреля 2020

В исходном вопросе вы хотите, чтобы они работали параллельно. Вы можете использовать Promise.all для запуска нескольких асин c задач, он будет ждать решения всех асин c задач и вернуть выходной массив.

Promise.all выполняет асин c задачи, выполняя их (последовательно), а не выполняет их технически параллельно, но они работают параллельно. Это даст вам результат, когда все асин c задачи будут решены или отклонены, если какая-либо из них не будет выполнена.

Или вы можете просто запустить их 1 на 1 без Promise.all. они не будут блокировать друг друга, поэтому по-прежнему параллельно, но вы Promise.all просто помогаете вам обрабатывать результаты обратного вызова в одном месте.

Выход будет 12 или 20, в зависимости от случайного времени ожидания, которое вы установили для Функции bar и foo.

Для состояния гонки только функции setTimeout являются асинхронными, но все операции в обратных вызовах являются синхронными и неблокирующими, поэтому поток не будет переходить от операций в одном обратном вызове к другому обратному вызову, если только все операции в этом обратном вызове завершены.

Но в JS при использовании SharedArrayBuffer может сохраняться гонка данных, для которой требуется объект Atomics для предотвращения гонки данных.

let output = 0;
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 = inputA;
    output = inputA + 1;
});
foo( () => {
    inputB--;
    inputA = inputB;
    output =  inputB * 2;
});


Promise.all([bar(),foo()])
.then(output => console.log('foo and bar tasks finished with output ',output));

setTimeout(() => {
    console.log('output variable value: ', output)
}, 2000);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...