小程序编译器性能优化之路
作者 | 马可
导读
小程序编译器是百度开发者工具中的编译构建模块,用来将小程序代码转换成运行时代码。旧版编译器由于业务发展,存在编译慢、内存占用高的问题,我们对编译器做了一次大规模的重构,采用自研架构,做了多线程、代码缓存、sourcemap 等多项优化,在性能和内存占用上都有很大提升。全文介绍了新版编译器的设计思路和优化方法,以及一些能够用在通用打包工具里的技术点。
全文6629字,预计阅读时间17分钟。
01 前言
小程序编译器在小程序开发、预览、发布各个阶段都需要使用,因此编译器性能会直接影响到开发者开发效率,也会影响到开发者工具的使用体验。
由于旧版的编译器(基于 webpack4)在构建大型项目时会很慢,内存占用也高,一直被开发者吐槽。我们经过大量的调研和开发,最后采用完全自研架构做新编译,针对小程序项目构建做了大量优化,基本解决了旧编译存在的问题。
下图是部分项目构建时间对比:
新版编译器相对于旧版实现了 2~7 倍的性能提升,并且支持实时编译、热重载等特性,内存占用更少,构建产物更优。
下面从 框架选型、新编译器工作原理、性能和产物优化方法 等方面介绍新版编译器的成长之路。
02 框架选型
在进行新版编译器设计时,需要明确当前的痛点问题:性能,优先解决性能问题。其他新技术和新想法对编译器有帮助的也一起实施。
旧版编译器基于 webpack4 存在如下几个问题:
-
大型项目构建速度太慢。
-
dev 启动慢、增量编译慢,仅支持 loader 缓存,bundle 无缓存也比较慢。
-
基于 webpack4 做扩展开发,需要 patch 部分模块才能工作,维护困难。
-
部分 webpack bundle 过程无法针对小程序代码结构进行优化,存在无效构建。
新编译的设计目标:
-
更快的全量编译速度,消除 webpack 存在的无效构建过程。
-
支持全缓存,加快首次和增量编译速度。
-
支持实时编译,减少 dev 启动和二次编译时间。
-
支持多线程编译加速,支持页面热重载。
-
优化产物结构,减少产物体积。
2.1 主流构建工具
下面介绍的是我们调研过的主流前端构建工具,每个工具都有适用场景和优缺点。
在新版本编译器架构设计时,其他构建工具的设计理念和技术特点都值得参考。
Webpack 构建过程:
Webpack 优点:功能完善、社区活跃、可配置性强、有很强的扩展性。
Webpack 缺点:配置复杂、构建速度慢,二次开发困难。
Parcel 构建过程:
Parcel 优点:无需配置,构建速度快,原生支持多线程和全缓存,多线程之间共享数据通过 lmdb 进行,避免跨线程通信开销。
Parcel 缺点:生态小,自定义性有限,大量采用 Node 插件,兼容性也差一些。
Vite 构建过程:
Vite 优点:配置较为简单,按需编译,启动快,dev 时有不错的体验。
Vite 缺点:生态小,dev 和 发布走两套构建流程。
其他小程序平台:
-
微信基于 gulp 和 C++ 模块做小程序构建,并且对 npm 模块做了预构建,在性能和开发体验上做的比较好。
-
支付宝基于 webpack 做小程序构建,并且使用了 esbuild 加速代码压缩。
-
抖音小程序使用自研编译器,构建流程比较简单。
2.2 新版编译器
在设计新编译框架时,借鉴了主流打包工具的工作流程,结合小程序代码特点,决定不做通用打包工具,重点优化小程序打包性能。
最终选择了自研编译器的方案,并做了大量优化工作,新版编译器优化点有如下几个方面:
1.支持多 Compiler 协同工作,将动态库开发等多类型项目构建解耦。
2.编译阶段全流程缓存,节省二次构建时间 90% 以上。
3.dev 开发默认采用按需编译,提升单页编译性能。
4.支持 babel 和 swc 多线程编译,提升全量编译速度 2 ~ 7 倍。
5.采用新版 sourcemap 协议,移除非必要解析合并,将 bundle 阶段耗时大幅缩减。
6.对 js、css、swan 模板编译均做了构建时标记优化,减少 bundle 合并耗时。
7.对于预览、发布阶段的 js 压缩和混淆,采用了 terser 和 esbuild 并行方案,esbuild 用于快速打出预览包,terser 可以保证压缩率用于发布包。
从结果看,新编译器从速度、资源占用和可维护性上相对于旧版都有显著的提升。
03 新版编译器工作原理
新编译器的处理流程和 parcel 比较类似,Compiler 控制处理流程,Processor 进行代码转换,基本流程如下:
其中几个重要的模块:
-
CompileEntry 编译器为入口模块,包含 cli 通信、dev server 通信、命令调用等。
-
CompileManager 为编译管理器,用于依赖资源下载和管理以及多个 Compiler 协同构建。
-
Compiler 为编译器模块,用于将项目源码编译成运行时代码,项目构建时 Compiler 可能有多个。
-
Processor 为单元处理器,用于处理 代码转换、代码合并 等单个编译任务。
注:小程序 App 项目有 1 个Compiler,动态库和动态扩展项目 2 个Compiler。
3.1 Compiler 编译器
用于编译单个小程序项目,将开发者原始代码编译为可运行代码。
工作职能:
1.创建运行上下文,提供 config、fs 文件处理、watcher 监控、logger 等模块,给 Processor 使用。
2.全量编译、文件变更时二次编译;这里二次编译也是走一遍全量编译流程,不过大部分用的是缓存结果。
3.管理、调度、运行 Processor 处理单元。
4.维护 Processor 依赖关系和结果缓存。
特点:
1.实现全流程缓存,将每个 Processor 的输入参数、输出结果写入缓存,在有缓存情况下二次编译时长可减少 90% 。
2.支持按需编译,每次按需单页编译、增量编译、全量编译 都走同样的 Processor 处理流程。
3.通过 Proxy 机制自动计算缓存参数依赖,不用手动为每个 Processor 生成缓存 hash,相对于 webpack 或 parcel 减少 bug 产生。
4.仅维护 Processor 依赖关系,不维护 ModuleGraph,简化处理流程。
关于全流程缓存每家打包器都有自己的实现方案,基本原理是根据当前输入参数和依赖情况为处理单元生成一个唯一 hash,hash 一致则结果一致。
webpack 和 parcel 由于维护了 ModuleGraph,缓存的计算和重用会复杂一些。小程序编译器仅根据 Processor 入参和调用依赖进行计算。
3.2 Processor 单元处理器
Processor 有如下特性:
1.在输入参数一致的情况下,保证输出一致,输入和输出都必须可序列化为 json ,实现了 Processor 全缓存。
2.Processor 中的 uri 为构建 ID,在单次构建过程中 ID 一致则处理结果一致,例如处理 app.js 文件,uri 为:js:app.js,好处是可以统一 Processor 资源处理路径。
3.Processor 之间支持互相调用:processWith 调用并继续执行,processWithResult 调用并等待返回结果。
注意:这里的输入参数包含 uri、app config, contextFreeData。
几种常用的 Processor:
1.JS Processor 将 es6 代码转换成 es5 代码,这是最耗时的模块。
2.Swan Processor 将 swan 模板代码转换成 view 层 js 代码。
3.Css Processor 使用 postcss 处理 css 中的单位转换、依赖收集等工作。
4.Bundle Processor 将前面 transformer 处理结果按照 bundle 算法合并文件并输出结果。
Processor 工作流程:
Processor 处理流程需要经过 transform -> bundle 的过程,在小程序里 js, css, swan 模板的 bundle 可以分开并行处理,这里和 webpack 的处理模式不一样,和 parcel 的 pipeline 类似。
3.3 性能和产物优化方法
3.3.1 多核心编译优化
由于 Node 中多线程模块初始化速度和通信效率比多进程好一些,新编译选择使用 多线程 做多核心优化。
多线程编译有 2 种方案选择:
-
方案1:基于 processor 做多线程调度,由于 processor 间支持相互调用,实际处理会很复杂且有通信成本。
-
旧的编译器做过基于webpack 的 workerthread-loader,性能提升有限(10%~15%)。
-
parcel 基于 lmdb 公共缓存消除线程间通信,保证读写效率,是一个比较好的解决方法。
-
方案2:仅对 js 转译做多线程调度,仅有一来一回 2 次通信成本。
-
使用 jest-worker 和 babel transform 做 js 多线程转译或者用 swc 多线程做 js 转译。
由于大部分构建时间在 js 转译这里(js 中有大量 node_modules 依赖,均需要转换),css 和 swan 模块转换耗时少。
最终选择方案2 仅做 js 多线程转译,处理流程简单且收益较好,整体提升如下:
-
使用 jest-worker 多线程 babel 转译,4 线程可提升 1 倍以上速度。
-
使用 swc 做 js 转译,4 线程提升 4 倍以上速度。
JS Processor 多线程处理:
其中:
uri: 为处理器构建 ID
contextFreeData: 单次构建中不可变数据,例如 app.json 中的配置项
context args:全局参数,例如优化实验开关、多线程开关等
在 js 转换处理时规定了 transformer 统一转换接口,基于接口实现了 babel 单线程、babel 多线程、swc 转换 3 种处理器,并且可随时做处理器切换。
对于不同的编译环境可以做到灵活设置:
1.开发者工具中开发者根据机器配置情况可以切换 多线程、swc 编译模式,提升效率。
2.云编译流水线默认开多线程编译提高性能。
3.webIDE 默认开单线程降低资源消耗。
3.3.2 SWC 编译优化
新编译器多线程模式相对于旧编译提升了 1 倍左右,在 dev 开发时一些大型项目页面首次编译还是有些慢,需要10秒以上,主要耗时在 js transform 这里。
swc 目前在 js 转译上基本成熟了,且大部分场景能提升 4 倍以上转译速度,因此增加了 swc 多线程转译支持,将大型项目页面首次编译控制在了 5 秒以内。
需要编写 2 个 swc 插件来适配 swc 转译:
-
@swanide/swc-require-rename 将 require/import/export 中的模块提取路径信息,以便于后续在 js 中分析模块依赖关系。
-
@swanide/swc-web-debug 对 js 代码进行插桩处理,用来支持真机调试中的断点调试。
swc 编译带来的性能提升是巨大的,在使用中也发现了一些问题:
1.swc 存在内存泄露,在 dev 阶段如果全量编译次数过多,会导致内存占用很高,需手动重启编译器。
2.swc 插件支持的 api 较少,一部分 babel 容易实现的功能,在 swc 中很难处理。
3.swc 由于使用 rust 编写插件,插件在不同 @swc/core 版本间不能通用,需要为不同平台生成 swc 插件,在部署上会麻烦一些。
在实际使用中,对于一部分 swc 不能很好处理的场景,会降级到 babel 处理。
3.3.3 代码压缩和运行时缓存
在 dev 阶段,编译后的代码是没有经过压缩的,可以在模拟器中运行。在预览发布阶段由于限制了包体积,需要做代码压缩以减少产物体积。
可选的代码压缩工具有如下 3 个:
1.terser 压缩率高,产物体积小,速度最慢。
2.swc 压缩快,mangle 支持不完善,压缩率较差。
3.esbuild 压缩最快(比 terser 快了 10 倍以上),支持 mangle,代码压缩率不如 terser。
最后经过对比考虑,选择了如下压缩方案:
1.预览阶段由于不需要 sourcemap,移除 sourcemap,并使用 esbuild 做代码压缩,提高预览速度(对于自动预览场景有很大提升)。
2.发布阶段使用 terser 做多线程压缩,并保留 sourcemap。
运行时缓存 指的是构建过程的中间结果都在内存中做了缓存,包括 Processor 处理结果 和 代码压缩结果,在二次构建时可以节省大部分重新构建时间。由于缓存中保留的是字符串和 json 对象,相对于基于 webpack 的旧版编译器有 40% ~ 60% 的内存节省,在内存占用上处于可接受范围。
3.3.4 Swan 模板处理优化
旧的 swan 模板处理使用 swan-loader 进行模板转换,由于设计时没有处理好模板 import 作用域,导致 标签以及 filter 过滤器函数只能内联到页面代码中,如果模板中大量使用了 template 和 filter,最终生成的代码体积会非常大。
新编编译器纠正了 import 作用域关系,将编译产物中的 template 、 filter 生成模式由内联改为 require 引用,然后在 bundle 阶段做代码合并,使相同模块能够得到重用,算是填了一个大坑。
新编译器 swan 模板处理流程:
单个 swan 文件经过 Processor 处理后可能的产物有:
-
component 组件模块,用于生成页面和自定义组件
-
template 模块
-
filter 过滤器函数、sjs 过滤器函数
-
transformed document 中间代码
将 swan 模板转换成不同类型的 js module,并维护依赖关系,便于后续的代码合并时更精细化的控制。
由于历史原因 import/include 中包含 sjs 或者 template 引用时不能直接生成 template 模块,需要在最后入口模板中生成。新编译也提供了 template静态编译选项,将严格限制 import 作用域,可直接生成 template 模块代码,对于 taro 生成的小程序项目可以节约 30% 左右的产物大小。
3.3.5 Sourcemap 优化
由于编译器需要支持 js 代码调试以及运行时 error 跟踪,在 dev 和发布阶段都需要生成 sourcemap。
在 webpack 中生成代码时需要对 sourcemap 进行合并计算,较大的项目 sourcemap 合并会占用很长时间,并且每次重新编译都要重新计算 sourcemap。
调研时发现浏览器 devtools 对 sourcemap 协议 的 index map 支持非常好, 新编译器基于 index map 协议做了 sourcemap 合并优化,由之前的多文件 sourcemap 合并计算,变成了计算生成 offset map 并拼接内容,这样 js bundle 耗时就由原来的 几秒到几十秒变为了固定 3 秒以内。
一个有意思的事情是 vscode 的 js-debugger 直到 22 年 6 月份才支持 index map 调试(index map 2011 年发布的),微软的动作稍微慢了一些。
3.3.6 后续工作
在新编译器开发完成之后的推广中,采用了渐进式推广方式:
第一阶段,开发者工具新旧编译器共存,dev、预览使用新编译器,发布使用旧编译器。
第二阶段,内部 pipeline 预览和发布全量使用新编译。
第三阶段,开发者工具全部切换到新编译器。
新版编译实际上线后还存在一些小的兼容性问题,需要尽量提前暴露问题才能做发布全量替换。
针对小程序项目,新编译做了大量的优化工作,部分优化工作还没有完成开发,包括:
hmr 热重载:开发中,由于 运行时框架、开发者工具均需要做接口适配,需要较长时间调试才能达到预期。
tree-shaking 代码消除:对于 es6 模块在 transform 阶段可以做 tree-shaking 消减代码。
scope-hoisting 作用域提升:理论可行,需要验证代码缩减效果。
新版编译器由于需要完全兼容旧版编译器构建结果,在 bundle 打包场景还存在优化空间,我们在后续工作中配合运行时框架可以做更多打包产物优化。
04 总结
新版编译器采用自研打包方案,对比基于 webpack 的旧编译器实现了巨大的性能提升,彻底解决了编译慢、资源占用高的问题,相对友商的编译器也有不错的性能优势。
一些新编译引入的优化手段如 swc 转译、esbuild 压缩、sourcemap 优化 也能用在其他前端项目构建中,并起到加速效果。
在新编译器项目中每个同学都非常努力,贡献了很多奇妙的点子,遇到的大部分难题都有效解决了。我们会继续坚持性能和产物优化这两个方向,不断提升开发者体验和运行时效率。
——END——
推荐阅读
百度APP iOS端包体积50M优化实践(六)无用方法清理
基于异常上线场景的实时拦截与问题分发策略
极致优化 SSD 并行读调度
AI文本创作在百度App发文的实践
DeeTune:基于 eBPF 的百度网络框架设计与应用
相关文章:
小程序编译器性能优化之路
作者 | 马可 导读 小程序编译器是百度开发者工具中的编译构建模块,用来将小程序代码转换成运行时代码。旧版编译器由于业务发展,存在编译慢、内存占用高的问题,我们对编译器做了一次大规模的重构,采用自研架构,做了多线…...
FFmpeg 命令:从入门到精通 | ffmpeg 命令分类查询
FFmpeg 命令:从入门到精通 | ffmpeg 命令分类查询 FFmpeg 命令:从入门到精通 | ffmpeg 命令分类查询ffmpeg -versionffmpeg -buildconfffmpeg -formatsffmpeg -muxersffmpeg -demuxersffmpeg -codecsffmpeg -decodersffmpeg -encodersffmpeg -bsfsffmpeg…...
Linux学习记录——삼십일 socket编程---TCP套接字
文章目录 TCP套接字简单通信1、服务端1、基本框架2、获取连接 2、客户端3、多进程4、多线程5、线程池6、简单的日志系统7、守护进程8、其它 TCP套接字简单通信 本篇gitee 学习完udp套接字通信后,再来看TCP套接字。 四个文件tcp_server.hpp, tcp_serve…...
【学习笔记】深度学习分布式系统
深度学习分布式系统 前言1. 数据并行:参数服务器2. 流水线并行:GPipe3. 张量并行:Megatron LM4. 切片并行:ZeRO5. 异步分布式:PATHWAYS总结参考链接 前言 最近跟着李沐老师的视频学习了深度学习分布式系统的发展。这里…...
【数据结构】树、二叉树的概念和二叉树的顺序结构及实现
目录 前言:一、树的概念及结构1.树的概念2.树的相关概念3.树的存储4.树在实际中的运用 二、二叉树概念及结构1.概念2.特殊的二叉树(1)满二叉树(2)完全二叉树 3.二叉树的性质4.二叉树的存储(1)顺序存储(2)链式存储 三、…...
rust学习-string
介绍 A UTF-8–encoded, growable string(可增长字符串). 拥有string内容的所有权 A String is made up of three components: a pointer to some bytes, a length, and a capacity. The length is the number of bytes currently stored in the buffer pub fn as_bytes(&…...
No167.精选前端面试题,享受每天的挑战和学习
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...
【python】pycharm导入anaconda环境
参考 Pycharm导入anaconda环境的教程图解 - 知乎 (zhihu.com)...
【数据结构】逻辑结构与物理结构
🦄个人主页:修修修也 🎏所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 🌳逻辑结构 1.集合结构 2.线性结构 3.树形结构 4.图形结构或网状结构 🌳物理结构 1.顺序存储结构 2.链式存储结构 结语 根据视点的不同,我…...
HTML5高级部分
目录 一、拖拽API1.1 拖拽元素1.2 监听事件1.3 dataTransfer传递数据 二、媒体API2.1 常用监听事件2.2 常用API 三、画布API3.1 canvas 标签3.2 创建canvas对象3.3 常用API 四、地理API4.1 方法 一、拖拽API 1.1 拖拽元素 页面中设置了draggable"true"的元素可以进…...
浏览器输入 URL 并回车发生了什么
本文节选自我的博客:浏览器输入 URL 并回车发生了什么 💖 作者简介:大家好,我是MilesChen,偏前端的全栈开发者。📝 CSDN主页:爱吃糖的猫🔥📣 我的博客:爱吃糖…...
asp.net core mvc 文件上传,下载,预览
//文件上传用到了IformFile接口 1.1文件上传视图 <form action"/stu/upload" method"post" enctype"multipart/form-data"><input type"file" name"img" /><input type"submit" value"上传&…...
Axios有哪些常用的方法?
Axios是一个常用的JavaScript库,用于进行HTTP请求。它提供了一组简洁而强大的方法来发送各种类型的请求,并处理响应数据。以下是Axios中一些常用的方法及其格式: GET请求: axios.get(url[, config]).then(response > {// 请求…...
PL/SQL+cpolar公网访问内网Oracle数据库
文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle,是甲骨文公司的一款关系…...
stable diffusion和gpt4-free快速运行
这是一个快速搭建环境并运行的教程 stable diffusion快速运行gpt快速运行 包含已经搭建好的环境和指令,代码等运行所需。安装好系统必备anaconda、conda即可运行。 stable diffusion快速运行 github: AUTOMATIC1111/稳定扩散网络UI:稳定扩散网页用户界…...
分享三个国内可用的免费GPT-AI网站
AIchatOS国内的不需要梯子 AItianhu同上 国内百度的文心一言一样非常优秀...
使用SDKMAN在Linux系统上安装JDK
本文使用的Linux发行版为Rocky Linux 9.2,可以当做CentOS的平替产品。 SDKMAN是一个sdk包管理工具,通过自带的命令可以快速切换软件环境, 官网地址:https://sdkman.io/。 1、安装sdkman: # curl -s "https://ge…...
MySQL(8) 优化、MySQL8、常用命令
一、MySQL优化 从上图可以看出SQL及索引的优化效果是最好的,而且成本最低,所以工作中我们要在这块花更多时间。 服务端参数配置; max_connections3000 连接的创建和销毁都需要系统资源,比如内存、文件句柄,业务说的支持…...
前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— Web APIs(三)
思维导图 全选案例 大按钮控制小按钮 小按钮控制大按钮 css伪类选择器checked <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><…...
嵌入式汇编大合集
嵌入式汇编 内联汇编的基本格式: asm volatile( /* volatile : 可选,禁止编译器对汇编代码进行优化 */"汇编指令" /* 汇编指令间使用\n分隔 */:"=限制符"(输出参数):"限制符"(输入参数):保留列表 )共四个部分:汇编语句,输出部分,输入部分…...
C#WPF框架MvvMLight应用实例
本文实例演示C#WPF框架MvvMLight应用实例。 目录 一、MVVM概述 二、MVVMLight概述 三、使用MVMLight框架 一、MVVM概述 MVVM概述MVVM是Model-View-ViewModel的简写,主要目的是为了解耦视图(View)和模型(Model)。...
【JVM】双亲委派模型
双亲委派模型 1. 什么是双亲委派模型2. 双亲委派模型的优点 1. 什么是双亲委派模型 提到 类加载 机制,不得不提的一个概念就是“双亲委派模型”。 双亲委派模型指的就是 JVM 中的类加载器如何根据类的全限定名找到 .class 文件的过程 类加载器: JVM 里面专门提供…...
多叉树+图实现简单业务流程
文章目录 场景整体架构流程业务界面技术细节小结 场景 这次遇到一个需求,大致就是任务组织成方案,方案组织成预案,预案可裁剪调整.预案关联事件等级配置,告警触发预案产生事件.然后任务执行是有先后的,也就是有流程概念. 整体架构流程 方案管理、预案管理构成任务流程的基础条…...
Word | 简单可操作的快捷公式编号、右对齐和引用方法
1. 问题描述 在理工科论文的写作中,涉及到大量的公式输入,我们希望能够按照章节为公式进行编号,并且实现公式居中,编号右对齐的效果。网上有各种各样的方法来实现,操作繁琐和简单的混在一起,让没有接触过公…...
leetCode 123.买卖股票的最佳时机 III 动态规划 + 状态压缩
123. 买卖股票的最佳时机 III - 力扣(LeetCode) 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意:你不能同时参与多笔交易࿰…...
JavaScript计算两个时间相差多少个小时的封装函数
js中计算两个时间相差小时数 在JavaScript中,你可以使用Date对象来处理日期和时间。下面是一个函数,它接受两个时间字符串作为参数,并返回两者之间的时间差(以小时为单位): function calculateHours(time…...
Qt 画自定义饼图统计的例子
先给出结果图,这个例子是将各种事件分类然后统计的其比例,然后画饼图显示出来 这个是我仿照官方给的例子,让后自己理解后,修改的,要生成饼图,需要QT的 charts 支持,安装QT 没有选择这个的&#…...
【数据结构】链表与LinkedList
作者主页:paper jie 的博客 本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。 本文录入于《JAVA数据结构》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精…...
Flink RoaringBitmap去重
1、RoaringBitmap的依赖 <!-- 去重大哥--> <dependency><groupId>org.roaringbitmap</groupId><artifactId>RoaringBitmap</artifactId><version>0.9.21</version> </dependency> 2、Demo去重 package com.gwm.driver…...
Elasticsearch—(MacOs)
1⃣️环境准备 准备 Java 环境:终端输入 java -version 命令来确认版本是否符合 Elasticsearch 要求下载并解压 Elasticsearch:前往(https://www.elastic.co/downloads/elasticsearch)选择适合你的 Mac 系统的 Elasticsearch 版本…...
网站建设人员安排/网站怎么做到秒收录
继续表格的有关操作,这篇说说表格行与列的删除。 所有这些操作恼人的地方其实都是在融合的单元格上 a.行的移除 首先计算整个表格的总列数。 总列数 var$row $(sender).parent().parent();var$nextRow $row.next();var$firstRow $row.parent().children("tr:fi…...
wordpress教程 微信/百度我的订单app
今天和大家分享一下win7系统删除MYSQL数据库提示操作无法完成问题的解决方法,在使用win7系统的过程中经常不知道如何去解决win7系统删除MYSQL数据库提示操作无法完成的问题,有什么好的办法去解决win7系统删除MYSQL数据库提示操作无法完成呢?小…...
北京专业做网站/潮州seo
(1) 查看在线的网络情况(2) 查询本机的端口号,主机IP(3)快速打开记事本,记录事件,Bug(4) 查询主机全部配置信息转载于:https://blog.51cto.com/9574626/1653491...
做海报的参考网站/搜索关键词优化排名
以前老用表格布局,总是要写很多代码,现在改成用DIV了,但是现在有很多地方还是需要表格布起来方便 ,但是要写的代码要太多,就从网上找了这个一段代码,省了不好在页面中的代码 dudley:expression(cellPadding…...
网站建设与维护的不足/宁波优化关键词首页排名
LeNet简介 LeNet-5出自论文Gradient-Based Learning Applied to Document Recognition,是一种用于手写体字符识别的非常高效的卷积神经网络。 卷积神经网络 卷积神经网络能够很好的利用图像的结构信息。LeNet-5是一个较简单的卷积神经网络。下图显示了其结构&…...
广州公司网站开发/温州seo网站建设
因特网使用的IP协议是无连接的,因此其传输是不可靠的。这样容易使人们感到因特网很不可靠,那为什么当初不直接把它设计为可靠的? 先打一个比方。邮局寄送的平信很像无连接的IP数据报。每封平信可能走不同的传送路径,同时平信也不保证不丢失。当我们发现收信人没有收到寄出的…...