允许IO和计时器在繁重的计算之间执行

时间:2017-05-25 10:11:17

标签: javascript node.js asynchronous

我需要在套接字服务器上的节点中进行一些CPU繁重的计算,但我不想阻止我的IO。

是否可以使用ES6 / ES7功能以很好的方式实现这一目标。

我的第一次尝试是使用async和await,但似乎如果在定时器事件之前调用了大量的同步函数,则只有在执行所有繁重的计算调用之后才会调用定时器事件。 https://jsfiddle.net/bz31vk97/1/

let t = 0
setInterval(async function() {
  t = t + 1
  console.log("timer: ", t)
}, 1000)

async function syncDelay(ms) {
  console.log("syncDelay: ", ms, "ms")
  let t1 = Date.now()
  while (Date.now() - t1 < ms) {}
  return ms
}

async function heavyWork() {
  for (let i = 0; i < 10; i++) {
    await syncDelay(500)
  }
}

heavyWork()
console.log("after calling heavyWork")

当我在节点上用setImmediate替换await调用时相同:

setImmediate(() => syncDelay(500))

两个版本首先调用所有syncDelays,然后才开始调用计时器事件。

有没有办法允许在几次cpu大量调用之间调用IO和timer事件?

1 个答案:

答案 0 :(得分:0)

我提出的一个解决方案是创建一个WorkManager,使其保持队列工作,并在上一个结束后将下一个工作添加到javascript eventloop。这样,其他事件可以在cpu繁重的工作负载部分之间插入。

https://jsfiddle.net/bz31vk97/2

let t = 0
setInterval(async function() {
  t = t + 1
  console.log("timer: ", t)
}, 1000)

async function syncDelay(ms) {
  console.log("syncDelay: ", ms, "ms")
  let t1 = Date.now()
  while (Date.now() - t1 < ms) {}
  return ms
}

class WorkManager {
  addWork(work) {
    if (this.first === undefined) {
      this.first = work
      this.last = work
      this.runWork()
    } else {
      this.last.next = work
      this.last = work
    }
  }
  newWork(fn, ...args) {
    this.addWork({fn, args})
  }
  runWork() {
    let work = this.first
    if (this.first === undefined) {
      return
    }
    setTimeout(() => {
      this.first = this.first.next
      work.fn(...work.args)
      this.runWork()
    }, 0)
  }
}

let wm = new WorkManager()
for (let i = 0; i < 10; i++) {
  wm.newWork(syncDelay, 500)
}

console.log("after calling heavyWork")