如何运行 并行执行两个setTimeout 任务?
How to run two setTimeout tasks in parallel?
我正在阅读 YDKJS 之前我们正在讨论异步、并行和并发代码之间的区别。
我有一个简单的异步示例:
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);
以上代码可以根据 Math.random 计时器和可变输出得到 2 个答案:
但是,我想增加一点复杂性并将 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);
对于您的原始问题,您希望同时查看它们 运行。您可以使用 Promise.all 到 运行 多个异步任务,它将等待所有异步任务解决并 return 一个输出数组。
Promise.all 通过迭代(串行)执行异步任务,技术上不是并行执行它们,但它们是 运行 并行执行。当所有异步任务都解决或拒绝(如果其中任何一个失败)时,它会给你一个结果。
或者你可以 运行 他们 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);
幸运的是,您要调用的竞争条件在普通 Javascript 中是不可能的。任何时候你有一个同步函数,一旦控制流传递给该函数,该函数绝对保证 运行 在环境 运行 中的任何其他 Javascript 之前结束(或抛出) s.
例如,给定 setTimeout
计划在接下来的 1-2 秒内(随机)发生的 1000 个任务,并且您还在 1.5 秒后调用以下函数:
const fn = () => {
console.log('1');
for (let i = 0; i < 1e8; i++) {
}
console.log('2');
};
一旦 fn
启动,它将在下一个随机函数 运行 之前 运行 所有代码(同步)。所以即使随机函数调用了console.log
,仍然可以保证,在上面的情况下,2
会在1
.
之后被记录。
所以,在你原来的例子中,只有两种可能性:
bar
的回调先 运行s,并完全结束,然后 foo
的回调 运行s,并完全结束。或者:
foo
的回调首先 运行s,并完全结束,然后 bar
的回调 运行s,并完全结束。
没有别的可能,即使随机超时落在完全相同的数字上。在任何给定时间,控制流只能位于代码中的 一处 。
我正在阅读 YDKJS 之前我们正在讨论异步、并行和并发代码之间的区别。
我有一个简单的异步示例:
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);
以上代码可以根据 Math.random 计时器和可变输出得到 2 个答案:
但是,我想增加一点复杂性并将 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);
对于您的原始问题,您希望同时查看它们 运行。您可以使用 Promise.all 到 运行 多个异步任务,它将等待所有异步任务解决并 return 一个输出数组。
Promise.all 通过迭代(串行)执行异步任务,技术上不是并行执行它们,但它们是 运行 并行执行。当所有异步任务都解决或拒绝(如果其中任何一个失败)时,它会给你一个结果。
或者你可以 运行 他们 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);
幸运的是,您要调用的竞争条件在普通 Javascript 中是不可能的。任何时候你有一个同步函数,一旦控制流传递给该函数,该函数绝对保证 运行 在环境 运行 中的任何其他 Javascript 之前结束(或抛出) s.
例如,给定 setTimeout
计划在接下来的 1-2 秒内(随机)发生的 1000 个任务,并且您还在 1.5 秒后调用以下函数:
const fn = () => {
console.log('1');
for (let i = 0; i < 1e8; i++) {
}
console.log('2');
};
一旦 fn
启动,它将在下一个随机函数 运行 之前 运行 所有代码(同步)。所以即使随机函数调用了console.log
,仍然可以保证,在上面的情况下,2
会在1
.
所以,在你原来的例子中,只有两种可能性:
bar
的回调先 运行s,并完全结束,然后foo
的回调 运行s,并完全结束。或者:foo
的回调首先 运行s,并完全结束,然后bar
的回调 运行s,并完全结束。
没有别的可能,即使随机超时落在完全相同的数字上。在任何给定时间,控制流只能位于代码中的 一处 。