是否可以定义一个不应跨越的边界,以便应用程序在任务调度(过度)使用方面能够很好地扩展?
问题:
- 执行 setTimeout 是否有一定的成本?比方说 0.1ms 或 CPU 时间?与在不同环境中生成线程相比,成本肯定要低几个数量级。但有吗?
- 对于需要 1-2 毫秒的微任务,是否最好避免使用 setTimout?
- 有什么不喜欢安排的事情吗?例如,我注意到在安排存储检索和其他事情时,IndexedDb 会出现某种写锁饥饿
- 可以安全地安排 DOM 操作吗?
我这么问是因为我开始使用 Scala.js和 Rx 实现 Monifu即大规模使用调度。有时一行代码会向事件循环的队列提交 5 个任务,所以基本上我会问自己,是否有类似任务队列溢出之类的东西会降低性能?我问这个问题尤其是在运行测试套件时,每秒可能有数百个任务排队。
这引出了另一个问题,是否可以列出何时应使用 RunNow/Trampoline 调度程序以及何时应使用与 Rx 有关的队列/异步调度程序的情况?每次我写类似 obs.buffer(3).last.flatMap{..}
这样的东西时,我都会想知道这个问题。它本身调度多个任务
最佳答案
关于 Monifu 中调度的一些注意事项 - Monifu 尝试崩溃异步管道,因此如果下游观察者本质上是同步的,那么 Monifu 将避免将任务发送到调度程序中。 Monifu 还具有背压功能,因此它控制有多少任务提交到调度程序中,因此您不会最终遇到浏览器队列爆炸的情况。
例如,像这样... Observable.range(0,1000).foldLeft(0)(_+_).map(_ + 10).filter(_ % 2 == 0)
仅在调度程序中发送单个任务以启动初始循环,否则,如果观察者也是同步的,则整个管道是完全同步的,并且不应在该队列中发送任何其他任务。它发送队列中的第一个任务,因为它不知道该源有多大,并且通常订阅数据源是与您不想阻止的某些 UI 更新相关的。
有 3 个较大的异常(exception):
- 您使用的数据源不支持背压(例如网络套接字连接)
- 您在接收方(即观察者)中有一个真正的异步边界,例如在与外部服务通信时可能会发生这种情况,并且这是一个您不知道何时完成的真正的 Future
一些可能的解决方案...
- 如果服务器通信不支持背压,在这种情况下,最简单的事情就是修改服务器以支持它 - 而且,正常的 HTTP 请求自然是背压的(即,它就像
Observable.interval(3.秒).flatMap(_ => httpRequest("..."))
- 如果这不是一个选项,Monifu 有缓冲策略...所以你可以有一个无界队列,但你也可以有一个触发缓冲区溢出并关闭连接的队列,或者尝试进行背压的缓冲,您还可以在缓冲区已满时开始删除新事件,我正在研究另一种缓冲策略来删除旧事件 - 目的是避免队列耗尽
- 如果您对无限个源使用“合并”,则不要这样做;-)
- 如果您正在向外部服务发出请求,请尝试优化这些请求 - 例如,如果您想通过将事件发送到网络服务来跟踪事件的历史记录,则可以对数据进行分组并执行批量请求等<
顺便说一句 - 关于浏览器端和任务调度的问题,我担心的一件事是 Monifu 不能足够有效地中断工作。换句话说,它可能应该将较长的同步循环分解为较小的循环,因为比性能问题更糟糕的是 UI 中可见的延迟问题,因为某些循环阻止了 UI 更新。我宁愿将多个较小的任务提交给调度程序,而不是一个较大的任务。在浏览器中基本上有 cooperative multi-tasking ,一切都在同一个线程上完成,包括 UI 更新,这意味着让某些工作阻塞该线程太长时间是一个非常糟糕的主意。
也就是说,我现在正在优化并更加关注 Javascript 运行时。在 setTimeout
上使用它是因为它比 setImmediate
更标准,不过我会在这些方面做一些工作。
但是,如果您有性能很差的具体示例,请传达它们,因为大多数问题都可以解决。
干杯,
关于javascript - Javascript事件循环任务队列可能溢出吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27305747/