【问题标题】:calculate execution times of async function over multiple calls计算多个调用的异步函数的执行时间
【发布时间】:2017-11-30 00:16:15
【问题描述】:

如果 do 工作函数正在执行某些操作,例如,从队列中挑选一个项目并执行某些操作。随着时间的推移,我将如何获得 doWork 函数的执行时间。我想知道doWork 平均需要多少时间才能完成。

示例代码

function doWork () {
  return Promise.resolve({first: 'Tony', last: 'Starks'})
}

async function wrapper () {
  console.time('wrapper')
  const response = await doWork()
  console.timeEnd('wrapper')
  return response
}

Promise.all([
  wrapper(),
  wrapper(),
  wrapper()
]).then((result) => console.info(result))

输出

wrapper: 0.388ms
[ { first: 'Tony', last: 'Starks' },
  { first: 'Tony', last: 'Starks' },
  { first: 'Tony', last: 'Starks' } ]
(node:2749) Warning: No such label 'wrapper' for console.timeEnd()
(node:2749) Warning: No such label 'wrapper' for console.timeEnd()

【问题讨论】:

  • 谨慎的做法是端到端运行您的函数测试,否则每次调用都将在有限的 CPU 时间中“与所有其他调用”“战斗”。一次进行一项性能测试,并以您现在的方式进行压力测试会更有意义。
  • 你基本上是在做console.time('wrapper') 三次,然后再做三次console.timeEnd('wrapper')。通过手动减去时间戳来衡量并行执行的任务。
  • How to measure the execution time of a promise? 的可能重复项,除非您的问题具体是为什么 console.time 方法不起作用(请edit 更清楚)。
  • @PatrickRoberts 不确定我明白你想说什么。
  • @Bergi 我发布的代码是对实际代码的过度简化。我已经建立了一个执行一堆任务的离线进程。我们不确定每个任务需要多长时间。理想情况下,这些任务中的每一个都可以是 AWS Lambda,但在不知道需要多长时间的情况下,我们不想采用 lambda 方式。

标签: node.js testing asynchronous promise performance-testing


【解决方案1】:

Related Question

为什么不使用内置的performance包,它默认在node和浏览器中可用。

以下内容也适用于多次调用...

async function timePromise(promiseFunction) {
  try {
    const begin = performance.now();
    await promiseFunction();
    const end = performance.now();
    const timeTaken_ms = end - begin;
    return timeTaken_ms;
  } catch (error) {
    console.error(error);
  }
}

【讨论】:

    【解决方案2】:

    如果您很难并行测试它们,我推荐这种方法:

    function doWork () {
      return Promise.resolve({ first: 'Tony', last: 'Stank' })
    }
    
    async function wrapper (index) {
      console.time(index)
      const response = await doWork()
      console.timeEnd(index)
      return response
    }
    
    Promise.all(
      Array(3) // some big number
        .fill(wrapper)
        .map((wrapper, index) => wrapper(index))
    ).then((results) => console.info(results))

    但是,JavaScript 是单线程的。您在同一滴答中初始化 3 个异步函数。它们最终会在每个异步回调上竞争 CPU 时间,正如您所观察到的,这会导致过度的时间延迟。

    比较上下时间;下面会快一个数量级,因为它们是串行初始化的,不会竞争 CPU 时间:

    function doWork () {
      return Promise.resolve({ first: 'Tony', last: 'Stank' })
    }
    
    async function wrapper ({ index, responses }) {
      console.time(index)
      responses.push(await doWork())
      console.timeEnd(index)
      return { index: ++index, responses }
    }
    
    Array(3) // some big number
      .fill(wrapper)
      .reduce(
        (promise, wrapper) => promise.then(wrapper),
        Promise.resolve({ index: 0, responses: [] })
      )
      .then(({ responses: results }) => console.info(results))

    【讨论】:

      【解决方案3】:

      如果您只是想让您的 console.time()console.end() 调用来解决您的异步函数,您可以在每次调用 console.time()console.end() 时生成一个唯一标签,以便测量仍然在同时进行多个呼叫时工作(因为每个呼叫都将使用自己的标签):

      let wrapperCntr = 0;
      
      async function wrapper () {
        let cnt = wrapperCntr++;
        console.time('wrapper' + cnt);
        const response = await doWork();
        console.timeEnd('wrapper' + cnt);
        return response;
      }
      

      【讨论】:

      • 根据您的建议更新问题。
      • @Perpetualcoder - 你为什么要用我的回答更新你的问题?这不是事情在这里应该如何运作的方式。您可以对我的回答做几件事,例如赞成、反对、评论、接受,但将其复制到您的问题中不是其中之一。你的问题应该保持原来的样子(有任何需要的澄清)。问题是问题,答案是答案,两者不应在堆栈溢出时合并。问题并不意味着对您的最新想法进行持续评论,并结合您从答案中学到的知识。
      • 好的。删除了更新。没有理由投反对票。我已经投了赞成票。但是,它并没有按照我想要的方式产生结果。但是您的解决方案克服了标签脱离上下文时引发警告的最初问题。
      • @Perpetualcoder - “你想要的结果”是什么?除了这个,我很难弄清楚你真正想要的是什么。
      • 我想知道每次调用需要多少时间(假设函数被调用 3 次)。由于 wrapperCntr,此方法隔离了每个调用,但是.. 第一次调用需要 0.6 毫秒,然后需要 2.6 毫秒等。我不认为这是正确的行为。
      猜你喜欢
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多