【问题标题】:How is async/await working in serial and parallel?async/await 如何以串行和并行方式工作?
【发布时间】:2018-01-10 18:30:47
【问题描述】:

我有两个async 函数。他们都在等待两个 3 秒的函数调用。但是第二个比第一个快。我认为更快的一个是并行运行,另一个是串行运行。我的假设正确吗?如果是,为什么会发生这种情况,因为这两个函数在逻辑上看起来都是一样的?

function sleep() {
  return new Promise(resolve => {
    setTimeout(resolve, 3000);
  });
}

async function serial() {
  await sleep();
  await sleep();
}

async function parallel() {
  var a = sleep();
  var b = sleep();
  await a;
  await b;
}

serial().then(() => {
  console.log("6 seconds over");
});

parallel().then(() => {
  console.log("3 seconds over");
});

【问题讨论】:

  • @Mjh Errm, setTimeout 本质上是异步的……而且 OP 代码中的几乎所有其他内容也是异步的……
  • @Frxstrem 除了setTimeout 根本不是异步的。它是一个同步函数,告诉事件循环稍后执行一个函数。这是一个机制,在这段代码中绝对没有异步。哪两个运动部件在不同的执行环境中以不同的速度运动?零。因此,这段代码根本不是异步的。
  • @Mjh 主上下文,setTimeout 的回调,serialparallel,以及对 .then 的两个调用的回调,都在不同的执行上下文中运行。跨度>
  • @Frxstrem 这一切都在同一个线程中工作,执行上下文没有什么不同,没有两个移动部分,有问题的函数setTimeout 是同步的。模拟异步行为的机制并不意味着某些东西是异步的。但是,嘿,如果你愿意相信它是 - 我只是一个凡人,告诉你一个你不喜欢的故事。
  • @Vadakkumpadath 不管怎样震撼你的世界,如果你无法区分通过事件循环通知线程和实际异步操作的 机制 之间的区别,那么好的,非常好,让我们在 javascript 世界中实现异步 :)

标签: javascript async-await ecmascript-2017


【解决方案1】:

Frxstream 已经有an excellent answer。以此为基础,并提供一些观点:

首先要认识到,Promise 是“热”创建的——也就是说,当您拥有一个 Promise 对象时,它已经“进行中”了。

第二个重要概念是await 类似于“异步等待”——也就是说,它暂停函数的执行,直到该承诺完成。

因此,serial 函数调用sleep,返回一个承诺,然后(异步)等待该承诺完成。 3 秒后该承诺完成后,serial 再次调用sleep,得到一个承诺,然后(异步)等待该承诺完成。该承诺在 3 秒后完成后,serial 完成。

parallel 函数调用sleep 并将其promise 存储在a 中,然后调用sleep 并将其promise 存储在b 中,然后(异步)等待a 完成。在a 3 秒后完成后,parallel(异步)等待b 完成。在b 几乎立即完成后,parallel 完成。

【讨论】:

    【解决方案2】:

    如果您像这样编写serial 函数会更清楚:

    async function serial() {
      var a = sleep(); //
      await a;         // await sleep();
    
      var b = sleep(); //
      await b;         // await sleep();
    }
    
    async function parallel() {
      var a = sleep();
      var b = sleep();
      await a;
      await b;
    }
    

    这里你可以清楚地看到,在serial函数中,第二个sleep()只在第一个sleep()完成后调用,而在parallel中,它在第一个完成之前立即调用,然后它等待两者都完成。因此,虽然它们可能看起来在功能上相同,但它们有细微的不同。

    【讨论】:

    • 介意你从这个问题的角度看一下:stackoverflow.com/q/46889290/919480 ?
    • @cogitoergosum - 我认为 Frxstrem 只是在解释您在问题中提出的不同之处,而不是建议您必须这样做。如果您希望操作连续运行(一个接一个),上面的serial 很好。上面的parallel 确实可以更好地实现为await Promise.all([sleep(), sleep()]);,但同样,我认为这不是上面答案的重点。上面的答案(我认为)的重点是解释问题的时间差异。
    • 另外,var a = sleep(); var b = sleep(); await a; await b; 也一样。
    【解决方案3】:

    因为sleep()函数是一个同步函数,它只是返回一个异步promise,例如:

    function sleep (time) {
        return new Promise((resolve) => setTimeout(resolve, time));
    }
    

    parallel()中,两个sleep()同步初始化两个promise,同时等待resolve,大概3s左右。

    但是,在serial() 中,两个await sleep() 意味着第二个sleep() 承诺必须等待第一个sleep() 被解析,所以大约需要6s。

    【讨论】:

      【解决方案4】:

      串行运行:一个接一个地运行函数

      // ? It’s slow! and use only for serial(one after another) run
      async function doThings() {
          const thing1 = await asyncThing1(); // waits until resolved/rejected
          console.log(thing1);
      
          const thing2 = await asyncThing2(); // starts only after asyncThing1() has finished.
          console.log(thing2);
      }
      
      doThings();
      

      并行运行:并行运行函数

      // ✅ async code is run in parallel!
      async function doThings() {
          const p1 = asyncThing1(); // runs parallel
          const p2 = asyncThing2(); // runs parallel
      
      
          // Method 1: Prefer => Promise.all()
          const [resultThing1, resultThing2] = await Promise.all([p1, p2]); // waits for all 
          // the promises get resolved or fails fast (If one of the promises supplied to it 
          // rejects, then the entire thing rejects).
      
          // Method 2: Not-Preferred
          const resultThing1 = await p1;
          const resultThing2 = await p2;
      
          console.log(resultThing1); // reaches here only after both the p1 & p2 have completed.
          console.log(resultThing2);
      }
      
      doThings();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-28
        • 2016-07-26
        • 2015-11-15
        • 2018-11-26
        • 2019-10-15
        • 2021-12-13
        • 1970-01-01
        相关资源
        最近更新 更多