当前位置: 首页 > news >正文

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码,顺便介绍了一下EventLoop,希望对大家有所帮助!

 

 

Event Loop

Event Loop 机制大家应该都有了解。我先重复总结一下。

Node.js 和 Javascript 的 Event Loop 不太一样,直观上是多了 setImmediateprocess.nextTick 两个 API。其次是由于运行时不一样,Html Standrad 里面会考虑多页面、DOM操作等不同来源会有不同的 task queue 。而 Node.js Event Loop 中需要考虑的没这么多。

按照我的理解,双方在概念上是一致的,可以如此概括(或者看这里):

  • task queue 任务队列。一些事件等会被定义为任务,很多时候会被称为 MacroTask(宏任务)与 MicroTask 进行对应。每次会获取队头的 task 进行执行。

  • microtask queue 微任务队列。会有一个微任务队列,一个 Task 内一般会执行清空微任务队列。

  • 如此往复。

性能测量

在上面的了解之后,有一个简单的对性能进行测量的方法:每秒内完成了多少次 Event Loop 循环,或者说执行了多少个 MacroTask,这样我们大致就能知道代码中同步的代码的执行情况。

测试函数

class MacroTaskChecker {constructor(macroTaskDispatcher, count = 1000, cb = () => { }) {this.macroTaskDispatcher = macroTaskDispatcherthis.COUNT = countthis.cb = cb}start(cb) {this.cb = cb || this.cbthis.stop = falseconst scope = () => {let count = this.COUNTconst startTime = performance.now()const fn = () => {count--if (count > 0) this.macroTaskDispatcher(fn)else {const endTime = performance.now()// 执行 COUNT 次宏任务之后 计算平均每秒执行了多少个this.cb({avg: this.COUNT / (endTime - startTime) * 1000,timestamp: endTime})!this.stop && this.macroTaskDispatcher(scope)}}this.macroTaskDispatcher(fn)}scope()}stop() {this.stop = true}
}

 之后,执行一些死循环去测试是否能检测到密集同步代码执行。

function meaninglessRun(time) {console.time('meaninglessRun')for (let i = time; i--; i > 0) {// do nothing}console.timeEnd('meaninglessRun')
}
setTimeout(() => {meaninglessRun(1000 * 1000 * 1000)
}, 1000 * 5)
setTimeout(() => {checker.stop()console.log('stop')
}, 1000 * 20)

 setTimeout

const checker = new MacroTaskChecker(setTimeout, 100)
checker.start(v => console.log(`time: ${v.timestamp.toFixed(2)} avg: ${v.avg.toFixed(2)}`))

 从输出中能明显看到同步阻塞的时候avg是下降的。不过在 browser 和 node.js 上测试两边会有明显差距。

// node.js
time: 4837.47 avg: 825.14
time: 4958.18 avg: 829.83
meaninglessRun: 918.626ms
time: 6001.69 avg: 95.95
time: 6125.72 avg: 817.18
time: 6285.07 avg: 635.16
// browse
time: 153529.90 avg: 205.21
time: 154023.40 avg: 204.46
meaninglessRun: 924.463ms
time: 155424.00 avg: 71.62
time: 155908.80 avg: 208.29
time: 156383.70 avg: 213.04

 

虽然达成我们的目的,但是使用 setTimeout 是不完全能准确记录下每一个任务的。根据 HTML Standrad 和 MDN 的说法,setTimeout 最少的会等待4ms。从这个角度看 browser avg * 4ms ≈≈ 1000ms。而 node.js 应该是没有遵循 browser 那边的约定,但是也没有执行到记录每一个loop。

setImmediate

如果使用 node.js 的 setImmediate

const checker = new MacroTaskChecker(setImmediate, 1000 * 10)

 可以看到执行次数大概高出 Node.js setTimeout 一个量级:

time: 4839.71 avg: 59271.54
time: 5032.99 avg: 51778.84
meaninglessRun: 922.182ms
time: 6122.44 avg: 9179.95
time: 6338.32 avg: 46351.38
time: 6536.66 avg: 50459.77

 

按照 Node.js 文档中的解释,setImmediate 会在每一个 loop (phase) 的 check 阶段执行。使用 setImmediate 应该是能准确记录每一次 Loop 的。我这台机器大概是 40000 到 60000 之间的循环次数。

window.postMessage

在 browser 上由于没有 setImmediate 我们可以按照 MDN 上的指引使用 window.postMessage 实现一个。

const fns = []
window.addEventListener("message", () => {const currentFns = [...fns]fns.length = 0currentFns.forEach(fn => fn())
}, true);
function messageChannelMacroTaskDispatcher(fn) {fns.push(fn)window.postMessage(1)
}

 可以看到和 node.js setImmediate 量级是一致的。

time: 78769.70 avg: 51759.83
time: 78975.60 avg: 48614.49
meaninglessRun: 921.143 ms
time: 80111.50 avg: 8805.14
time: 80327.00 avg: 46425.26
time: 80539.10 avg: 47169.81

 

MessageChannel

browser

理论上 browser 使用 MessageChannel 应该也是可以的,还避免了无效的消息被其他 window.addEventListener("message", handler) 接收:

const { port1, port2 } = new MessageChannel();
const fns = []
port1.onmessage = () => {const currentFns = [...fns]fns.length = 0currentFns.forEach(fn => fn())
};
function messageChannelMacroTaskDispatcher(fn) {fns.push(fn)port2.postMessage(1)
}

 不是很懂为啥会比 window.postMessage 频繁一点,同时启动两个 checker 的话可以看到 log 是成对出现的,也就是说一个loop内大家都只执行了一次。我猜测是 window.postMessage 的实现方式消耗会大一些。

time: 54974.80 avg: 68823.12
time: 55121.00 avg: 68493.15
meaninglessRun: 925.160888671875 ms
time: 56204.60 avg: 9229.35
time: 56353.00 avg: 67430.88
time: 56503.10 avg: 66666.67
// 一起执行 wp=window.postMessage mc=MessageChannel
wp time: 43307.90 avg: 25169.90
mc time: 43678.40 avg: 27005.13
wp time: 43678.60 avg: 26990.55
mc time: 44065.80 avg: 25833.12
wp time: 44066.00 avg: 25819.78
mc time: 44458.40 avg: 25484.20

 

node

在 node.js 上也有 MessageChannel ,是否也可以用来测量loop次数呢?

mc time: 460.99 avg: 353930.80
mc time: 489.52 avg: 355088.11
mc time: 520.30 avg: 326384.64
mc time: 551.78 avg: 320427.29

 量级很不正常。理论上不应该超过 setImmediate 的。如果同时启动 setImmediatesetTimeout 的 checker:

...
(messagechannel) time: 1231.10 avg: 355569.31
(messagechannel) time: 1260.14 avg: 345825.77
(setImmediate) time: 1269.95 avg: 339.27
(setTimeout) time: 1270.09 avg: 339.13
(messagechannel) time: 1293.80 avg: 298141.74
(messagechannel) time: 1322.50 avg: 349939.04
...

 

很明显跟不是宏任务了。我猜测 MessageChannel 在 node.js 被归入到跟 socket 等同级别了,就是超出阈值之后的任务会移动到下一个loop中。

总结

使用这种方式去检测性能还挺有趣的,正式使用的话这个指标感觉过于不稳定(即使什么都没做都会有20%-30%的振动)。推荐和其他正经的办法(比如 performance 等)结合。

同时这种方式非常有可能影响正常的 Event Loop,比如 Node.js 中会有一个 pull 的阶段,在执行完全部微任务后,没有任何 timer 的话是会停留在这个阶段,准备马上执行下一个出现的微任务。

顺便复习了下 Event Loop。没想到的是 MessageChannel 在两边的差距居然有这么大。

相关文章:

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码,顺便介绍了一下EventLoop,希望对大家有所帮助! Event Loop Event Loop 机制大家应该都有了解。我先重复总结一下。 Node.js 和 Javascript 的…...

1018 锤子剪刀布 1025 反转链表

现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。 输入格式: 输入第 1 行给出正整数 N(≤10 5 ),即双方交锋的次数。随后 N 行,每行给出一次交锋的信…...

卷积神经网络的原理及实现

专栏:神经网络复现目录 卷积神经网络 本章介绍的卷积神经网络(convolutional neural network,CNN)是一类强大的、为处理图像数据而设计的神经网络。 基于卷积神经网络架构的模型在计算机视觉领域中已经占主导地位,当今…...

【C++知识点】重载

✍个人博客:https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 📚专栏地址:C/C知识点 📣专栏定位:整理一下 C 相关的知识点,供大家学习参考~ ❤️如果有收获的话,欢迎点赞👍…...

apscheduler三种定时触发方式

#第一种# date: 特定的时间点触发# 2019-01-01 00:00:00 准时执行# import time # from apscheduler.schedulers.blocking import BlockingScheduler # # def my_job(): # print(time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(time.time()))) # sched BlockingSchedu…...

802.11 service服务类型

802.11 serviceservice定义service分类按照模块分为两类按照功能分为六类数据传输相关服务分布式服务DS(Distribution Service)整合服务IS(Integration Service)关联(association)重关联(reasso…...

pytest测试框架——allure报告

文章目录一、allure的介绍二、allure的运行方式三、allure报告的生成方式一、在线报告、会直接打开默认浏览器展示当前报告方式二、静态资源文件报告(带index.html、css、js等文件),需要将报告布置到web服务器上。四、allure中装饰器1、实现给…...

SQLI-Labs(3)8-14关【布尔盲注和时间盲注】

目录 第八关 第九关: 第十关 第十一关 第十二关 第十三关 第十四关 第八关 我们用测试语句来测试是否为注入点 从上图中得知存在注入点,那么接下来就是爆列 一共有三列,接下来用union select 和报错注入都试一下发现没有回显点&…...

ESP32学习笔记03-日志打印

ESP32日志 日志分为5个等级 ESP_LOGE - error (lowest)ESP_LOGW - warningESP_LOGI - infoESP_LOGD - debugESP_LOGV - verbose (highest)API 0.头文件 #include "esp_log.h"1.给一个日志标签设置等级...

mongoTemplate非string类型模糊查询

需求 为方便使用人员对任务Task的搜索,需要根据number实现模糊搜索。 背景 之前设计的number是long类型,但是mongodb只支持string类型的正则匹配。 方案 修改number为string类型;新增一个冗余字段,用于模糊查询;在…...

Redis是单线程还是多线程?Redis的10种数据类型,有哪些应用场景?

目录专栏导读一、同样是缓存,用map不行吗?二、Redis为什么是单线程的?三、Redis真的是单线程的吗?四、Redis优缺点1、优点2、缺点五、Redis常见业务场景六、Redis常见数据类型1、String2、List3、Hash4、Set5、Zset6、BitMap7、Bi…...

到底什么才是幻读?

💗推荐阅读文章💗 🌸JavaSE系列🌸👉1️⃣《JavaSE系列教程》🌺MySQL系列🌺👉2️⃣《MySQL系列教程》🍀JavaWeb系列🍀👉3️⃣《JavaWeb系列教程》…...

RPC重试机制和控制方案

重试机制 因为网络抖动等原因导致 RPC 调用失败,这时候使用重试机制可以提高请求的最终成功率,减少故障影响,让系统运行更稳定。 重试简易实现方案 在重试的过程中,为了能够在约定的时间内进行安全可靠地重试,在每次…...

【无标题】动态给结构体赋值

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[20]; double score; } Student; int main() { Student *p (Student *)malloc(sizeof(Student)); if (p NULL) { printf(“Memory allocation failed.”…...

centos7 soft raid每周自动同步的问题

之前redhat老版本时也遇到过这样的问题https://blog.csdn.net/jolly10/article/details/108768360centos7解决的办法略有不同&#xff0c;记录一下&#xff1a;centos7默认是每周日凌晨1点进行raid检查&#xff0c;有点太频繁了[oracleqht117 data]$ ls /etc/cron*/etc/cron.de…...

嵌入式Linux内核代码风格

这是一个简短的文档&#xff0c;描述了linux内核的首选代码风格。代码风格是因人而异的&#xff0c;而且我 不愿意把我的观点强加给任何人&#xff0c;不过这里所讲述的是我必须要维护的代码所遵守的风格&#xff0c; 并且我也希望绝大多数其他代码也能遵守这个风格。请在写代码…...

Andorid:关于Binder几个面试问题

1.简单介绍下binderbinder是一种进程间通讯的机制进程间通讯需要了解用户空间和内核空间每个进程拥有自己的独立虚拟机&#xff0c;系统为他们分配的地址空间都是互相隔离的。如两个进程需要进行通讯&#xff0c;则需要使用到内核空间做载体&#xff0c;内核空间是所有进程共享…...

【剑指Offer-Java】包含min函数的栈?

题目 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中&#xff0c;调用 min、push 及 pop 的时间复杂度都是 O(1)。 MinStack minStack new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.min()…...

红队APT——邮件钓鱼攻击SwaksOffice漏洞RLO隐藏压缩释放

目录 (一)采用自己搭建Ewomail配合Swaks 0x01 搭建过程 0x02 配置转发信息 (二)网页钓鱼-克隆修改...

【Java|基础篇】超详细讲解运算符

文章目录1. 什么是运算符2. 算术运算符隐式类型转换强制类型转换字符串的拼接字符相加自增和自减运算符3.赋值运算符4. 关系运算符5. 逻辑运算符短路与(&&)和短路或(||)6.三目运算符7. 位运算符8. 移位运算1. 什么是运算符 运算符用于执行程序代码运算&#xff0c;会针…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

Mysql故障排插与环境优化

前置知识点 最上层是一些客户端和连接服务&#xff0c;包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念&#xff0c;为通过安全认证接入的客户端提供线程。同样在该层上可…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...

Android屏幕刷新率与FPS(Frames Per Second) 120hz

Android屏幕刷新率与FPS(Frames Per Second) 120hz 屏幕刷新率是屏幕每秒钟刷新显示内容的次数&#xff0c;单位是赫兹&#xff08;Hz&#xff09;。 60Hz 屏幕&#xff1a;每秒刷新 60 次&#xff0c;每次刷新间隔约 16.67ms 90Hz 屏幕&#xff1a;每秒刷新 90 次&#xff0c;…...