Javascript事件循环任务队列是否可能溢出?

时间:2014-12-04 22:55:54

标签: javascript asynchronous event-loop scala.js monifu

是否有可能定义一个不应跨越的边界,以便应用程序在任务调度(过度)使用时能够很好地扩展?

问题:

  1. 执行setTimeout会有一定的成本吗?假设0.1ms或CPU时间?与在不同环境中生成线程相比,成本肯定要低一些。但有没有?
  2. 最好避免将setTimout用于需要1-2毫秒的微任务吗?
  3. 有什么不喜欢安排的吗?例如,在调度存储检索和其他事情时,我注意到写锁的某种IndexedDb饥饿
  4. 可以安全地安排DOM操作吗?
  5. 我问,因为我开始使用Scala.js和正在大规模使用调度的Rx实现Monifu。有时,一行代码将5个任务提交给事件循环的队列,所以基本上我都在问自己,有没有像任务队列溢出那样会降低性能的速​​度?我特别是在运行测试套件时会问这个问题,每秒可能会有数百个任务入队。

    这引出了另一个问题,是否可以列出一个应该使用RunNow / Trampoline调度程序以及何时使用Quex / Async调度程序进行Rx的情况?每次我写obs.buffer(3).last.flatMap{..}之类的东西时,我都在想这个问题,{{1}}本身安排了多个任务

1 个答案:

答案 0 :(得分:1)

Monifu中有关调度的一些注意事项--Monifu尝试折叠异步管道,因此如果下游观察者本质上是同步的,那么Monifu将避免将任务发送到调度程序。 Monifu也会进行反压,因此它控制向Scheduler提交的任务数量,因此您无法在浏览器队列崩溃的情况下结束。

例如,类似这样的事情...... Observable.range(0,1000).foldLeft(0)(_+_).map(_ + 10).filter(_ % 2 == 0)只是在调度程序中发送一个任务来启动那个初始循环,否则如果观察者也是同步的并且不应该发送任何一个,那么整个管道是完全同步的该队列中的其他任务。并且它发送队列中的第一个任务,因为它不知道该源的大小,并且通常订阅数据源是关于一些您不想阻止的UI更新。

有三大例外:

  1. 您正在使用不支持背压的数据源(如网络套接字连接)
  2. 你在接收器(即观察者)中有一个真正的异步边界,这可能发生在例如与外部服务通信时,以及你不知道什么时候真正的未来将完成
  3. 可能有一些解决方案......

    1. 如果服务器通信不支持背压,在这种情况下最简单的方法是修改服务器以支持它 - 同样,正常的HTTP请求自然会被压力(即它&# 39;和Observable.interval(3.seconds).flatMap(_ => httpRequest("..."))
    2. 一样简单
    3. 如果那不是一个选项,Monifu有缓冲策略......所以你可以有一个无界的队列,但是你也可以有一个触发缓冲区溢出的队列并关闭连接,或者尝试做的缓冲背压,你也可以在缓冲区已满时开始删除新事件,并且我正在制定另一个缓冲旧事件的缓冲策略 - 目的是避免被炸成队列
    4. 如果您正在使用"合并"在可以无限制的来源上,然后不要这样做; - )
    5. 如果您正在对外部服务进行请求,请尝试优化这些请求 - 例如,如果您希望通过将事件发送到Web服务来跟踪事件的历史记录,则可以对数据进行分组并执行批处理请求等等
    6. BTW - 关于浏览器端和任务安排问题,我担心的一件事是Monifu不会有效地破坏工作。换句话说,它可能应该将更长的同步循环分解为更小的同步循环,因为比遇到性能问题更糟糕的是在UI中可见的延迟问题,因为某些循环阻止了您的UI更新。我宁愿将多个较小的任务提交给调度程序,而不是更大的任务。在浏览器中你基本上有cooperative multi-tasking,所有内容都在同一个线程上完成,包括UI更新,这意味着让一段时间阻止这个线程的工作是一个非常糟糕的主意。

      那就是说,我现在正在优化并更加关注Javascript运行时。 setTimeout正在使用它,因为它比setImmediate标准更高,但我会在这些方面做一些工作。

      但如果您的具体样本性能很差,请与他们沟通,因为大多数问题都可以解决。

      干杯,