Android渲染系列之原理概述篇
屏幕硬件
渲染离不开屏幕,Android中的屏幕碎片化比较严重,尺寸大小不一,材质也是屏幕重要的因素。 目前智能手机主流的屏幕可分为两大类即液晶显示器;
- LCD (Liquid Crystal Display) 液晶显示器
- OLED (Organic Light Emitting Diode)即有机发光二极管
CPU与GPU
除了屏幕 UI渲染还要依赖另外两个核心的硬件: 「CPU」 和 「GPU」。
- CPU (Central Processing Unit,中央处理器),是计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元
- GPU (Graphics Processin Unit,图形处理器),是一种专门用于图像运算的处理器,在计算机系统中通常被称为"「显卡」"的核心部件就是 GPU。
UI 组件在绘制到屏幕之前,都需要经过 Rasterization (栅格化)操作,而栅格化又是一个非常耗时的操作。GPU的引入就是为了加快栅格化
GPU简述
在没有 GPU 的时代,UI 的绘制任务完全由 CPU 完成,CPU 既要负责 UI 绘制还要负责内存管理、逻辑运算等其他任务,这就导致 CPU 的任务繁多,因此性能也会有影响. CPU与GPU 在结构设计上完全不同,如下图:
- 黄色 Control 为控制器,用于协调控制整个 CPU 的运行,包括指令读取、控制其他模块的运行等;
- 绿色的 ALU (Arithmetic Logic Unit) 是算数逻辑单元,用于进行数学、逻辑运算;
- 橙色的 Cache 和 DRAM 分别为高速缓存和 RAM,用于存储信息
从上图可以看出,CPU 的控制器较为复杂,而 ALU 数量较少,因此 CPU 更擅长各种复杂的逻辑运算,但不擅长数学尤其是浮点运算 而 GPU 的设计正是为实现大量数学运算。GPU 的控制器比较简单,但包含大量 ALU。GPU 中的 ALU 使用了并行设计,且具有较多的浮点运算单元。「可以帮助我们加快栅格化操作」。
在处理3D场景时,通常Android使用OpenGL ES,不过在Android 7.0 添加了对 Vulkan 的支持
Vulkan 的设计目标是取代 OpenGL,Vulkan 是一个相当低级别的 API,并且提供并行的任务处理。Vulkan 还能够渲染 2D 图形应用程序。除了其较低的 CPU 使用率,Vulkan 还能够更好地在多个 CPU 内核之间分配工作。在功耗、多核优化提升绘图调用上有着非常明显的优势。
而且从性能考虑,「GPU是用户进程唯一可以直接操作的硬件」,是个特例
这与Android 「Client-Sever」 架构不同,一般情况下 应用与硬件交互都需要经过binder委托给系统服务
软件绘制与硬件绘制
有了GPU,便可以在渲染中加速栅格化的过程,软件绘制往往是cpu借助2d渲染引起skia的能力,去完成渲染,一般实在低端机器
软件绘制使用 Skia 库,它是一款能在低端设备,如手机呈现高质量的 2D 跨平台图形框架,类似 Chrome、Flutter 内部使用的都是 Skia 库
Android图形系统
有了上面知识之后,我们视角切入到Android系统中来,先来看下Android的图像系统组件 无论开发者使用什么渲染 API,一切内容都会渲染到 「Surface」 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。
图形架构
下图显示了关键组件如何协同工作
我们可以看到 有关键的两个角色,
- IMAGE STREAM PRODUCERS(图像生产者)、
- 另外一个叫IMAGE STREAM CONSUMERS (图像消费者),
整个图形渲染系统就是采用了**「生产者消费者模式」**。屏幕渲染的核心,是对图像数据的生产和消费。 「生产和消费的对象,是BufferQueue 里的 Buffer」。
数据流
这是描述Buffer是如何流动起来的,是对上面流程的的数据化抽象
左侧的对象是生成图形缓冲区的渲染器,如主屏幕、状态栏和系统界面。SurfaceFlinger 是合成器,而硬件混合渲染器是混合渲染器。
「BufferQueues 是 Android 图形组件之间的粘合剂」。它们是一对队列,可以调解缓冲区从生产方到消耗方的固定周期。一旦生产方移交其缓冲区,SurfaceFlinger 便会负责将所有内容合成到显示部分。 抽象成生成消费者模型的 BufferQueue 通信过程
BufferQueue 包含将图像流生产方与图像流消耗方结合在一起的逻辑。
- 图像生产方的一些示例包括由相机 HAL 或 OpenGL ES 游戏生成的相机预览。
- 图像消耗方的一些示例包括 SurfaceFlinger 或显示 OpenGL ES 流的另一个应用,如显示相机取景器的相机应用。
BufferQueue 是将缓冲区池与队列相结合的数据结构,它使用 Binder IPC 在进程之间传递缓冲区。
Vsync 有两种,Vsync-app 和 Vsync-sf,前者用于告诉 Choreographer,是时候协调 app 生产buffer了;后者用于告诉 SurfaceFlinger,是时候来消费buffer合成并显示到屏幕了
如果把应用程序图形渲染过程当做一次绘画过程,那么绘画过程中 Android 的各个图形组件的作用是:
- 画笔: Skia 或者 OpenGL。我们可以用 Skia 画笔绘制 2D 图形,也可以用 OpenGL 来绘制2D/3D 图形。正如前面所说,前者使用 CPU 绘制,后者使用 GPU 绘制。
- 画纸: Surface。所有的元素都在 Surface 这张画纸上进行绘制和渲染。在 Android 中Window 是 View 的容器,「每个窗口都会关联一个 Surface」。而 「WindowManager 则负责管理这些窗口,并且把它们的数据传递给 SurfaceFlinger」。
- 画板: Graphic Buffer。Graphic Buffer 缓冲用于应用于应用程序图形的绘制,「在 Android4.1 之前使用的是双缓冲机制;在 Android 4.1之后,使用的是三缓冲机制」。
- 显示: SurfaceFlinger。它将 WindowManger 提供的所有 Surface,通过硬件合成器Hardware Composer 合成layer并输出到显示屏。
使用画笔 Skia /OpenGL 将内容绘制到 Surface 上,
「绘制的过程中如果使用 Open GL 渲染,那便是硬件加速」,否则纯靠 CPU 绘制染栅格化的过程就叫软件绘制。对于硬件绘制,我们通过调用 OpenGL ES 接口利用 GPU 完成绘制。
对 BufferQueue 理解了的话,那么可以延伸思考一下:
- 生产者何时 dequeueBuffer,消费者何时 require Buffer?两者是怎么协调工作的?
- BufferQueue 里可能会有多少个 Buffer?里面含有不同数目的 Buffer,对 App 的显示工作(具体来说,就是帧率)会有怎样的影响?
要了解这两个问题,就要了解:
- Choreographer 和 Vsync
- Double Buffer 和 Triple Buffer
更多精彩内容关注公众号 「Android茶话会」
这在后面会有介绍
渲染系统的持续演进
为了使AndroidUI更加的丝滑,渲染系统也是下足了功夫,在持续演进,
Android 4.0 默认开启硬件加速
- Android 3.0,API 11开始引入硬件加速
Android 2D 渲染管道支持硬件加速,也就是说,在 View 的画布上执行的所有绘制操作都会使用 GPU。启用硬件加速需要更多资源,因此应用会占用更多内存
- Android4.0,API 14默认开启硬件加速
由于现在Android4.4以下的手机基本已被淘汰,所以以后的版本默认都是开启了硬件加速。
软件渲染
再没有硬件加速之前主要是通过skia这种软件方式来渲染UI,如下图所示
整个流程如上图所示:
- Surface:每个 View 都由某一个窗口管理,而每一个窗口都会关联有一个 Surface。
- Canvas:通过 Surface 的 Lock 函数获得一个 Canvas,「Canvas 可以简单理解为 Skia 底层接口的封装」。
- Graphic Buffer:SurfaceFlinger 会帮助我们托管一个 BufferQueue,我们从 BufferQueue中拿到 Graphic Buffer,然后**「通过 Canvas 以及 Skia 将绘制内容栅格化到上面」**
- SurfaceFlinger:通过 Swap Buffer 把 Front Graphic Buffer 的内容交给 SurfaceFlinger,最后硬件合成器 Hardware Composer 合成并输出到显示屏。
整个渲染流程看上去比较简单,但是正如前面所说,CPU 对于图形处理并不是那么高效,这个过程完全没有利用 GPU 的高性能。
硬件加速
Android3.0,支持硬件加速,需要手动打开,Android4.0就默认开启硬件加速了,开启硬件加速流程如下
硬件加速绘制最核心就是通过 GPU 完成 Graphic Buffer 的内容绘制。 在Android 5.0之前,Android应用程序的Main Thread不仅负责用户输入,同时也是一个OpenGL线程,也负责渲染UI。通过引进Render Thread,我们就可以将UI渲染工作从Main Thread释放出来,交由Render Thread来处理,从而也使得Main Thread可以更专注高效地处理用户输入,这样使得在提高UI绘制效率的同时,也使得UI具有更高的响应
此外硬件绘制还引入了一个 DisplayList 的概念,每个 View 内部都有一个DisplayList,当某个 View 需要重绘时,将它标记为 Dirty。当需要重绘时,仅仅只需要重绘一个 View 的 DisplayList,而不是像软件绘制那样需要向上递归。这样可以大大减少绘图的操作数量,因而提高了渲染效率
Android 4.1黄油计划(Project Butter)
Google 在 2012 年的 I0 大会上宣布了 Project Butter 黄油计划,并且在Android 4.1 中正式开启了这个机制。 Project Butter 主要包含三个组成部分,
- VSYNC
- Triple Buffer
- Choreographer。
其中 VSYNC (Vertical Synchronization) 是理解 Project Butter 的核心
Vsync
对于 Android 4.0 CPU 可能会因为在忙其他的事情,导致没来得及处理 UI 绘制,导致卡顿。 为了解决这个问题,Project Butter 引入了 VSYNC,「它类似于时钟中断,每收到 VSYNC 中断,CPU 会立即准备 Buffer 数据」,
由于大部分显示设备刷新频率都是 60 Hz (一秒刷新 60次) ,也就是说一数据的准备都要在 16ms 内完成
这样应用总是在 VSYNC 边界上开始绘制,而 SurfaceFlinger 总是在 VSYNC 边界上进行合成。这样可以消除卡顿,并提升图形的视觉表现。
三缓冲机制(Triple Buffering)
在Android 4.1 之前,Android 使用双缓冲机制。
通常不同的 View 或者Activity 都会共用同一个 Window,也就是共用同一个 Surface。而每个 Surface 都会有一个 BufferQueue 缓存队列,但是这个队列会由 SurfaceFlinger 管理通过匿名共享内存机制与 App 应用层交互
从上图可以看出
- 每个 Surface 对应的 BufferQueue 内部都有两个 Graphic Buffer,一个用于绘制一个用于系那是。应用会把内容先绘制到离屏缓冲区 (OffScreen Buffer) ,在需要显示时,才把离屏缓冲区的内容通过 Swap Buffer 复制到 Front Graphic Buffer 中。
- 这样 SurfaceFlinge 就拿到了某个 Surface 最终要显示的内容,
但是同一时间我们可能会有多个 Surface。这里面可能是不同应用的 Surface,也可能是同一个应用里面类似SurfaceView 和 TextureView,它们都会有自己单独的 Surface。
- 这个时候 SurfaceFlinger 把所有 Surface 要显示的内容统一交给 Hardware Composer,它会根据位置、Z- Order 顺序等信息合成为最终屏募需要显示的内容,而这个内容交给系统的顿缓冲区 Frame Buffer 来显示 (Frame Buffer 是非常底层的,可以理解为屏幕显示的抽象)
如果只有两个Graphic Buffer 缓存区A和 B,如果 CPU/GPU 绘制过程较长,超过了一个 VSYNC 信号周期,因为缓冲区 B 中的数据还没有准备完成,所以只能继续展示A 缓冲区的内容,这样缓冲区A和 B 都分别被显示设备和 GPU 占用,CPU 无法准备下一的数据,如下所示
如果再提供一个缓冲区,CPU、GPU 和显示设备都能使用各自的缓冲区工作,互不影响。 简单来说,三缓冲机制就是在双缓冲机制的基础上增加了一个 Graphic Buffer 缓冲区,这样可以最大限度的利用空闲时间,
带来的坏处是多使用了一个 Graphic Buffer 所占用的内存。
我们看到,在第一次Jank内,CPU使用了第三块缓冲区,自己计算了C帧的数据,
假如此时没有三缓冲,那么cpu就只能再继续等下一个vsync信号,也就是在图中蓝色A块的地方,才能开始计算C帧数据,就又引发下一次卡顿。
我们看到,「通过引入三缓冲,虽然不能避免卡顿问题,但是却可以大幅优化卡顿问题」,尤其是**「避免连续卡顿」,但是,三缓冲也有缺点,就是「内存消耗多」**,所以系统并非一直开启三缓冲,要想真正解决问题,还需要在cpu层对数据尽量优化,从而减小cpu和gpu的计算量,
编舞者Choreographer
这个名字起的非常贴合且很文艺,舞蹈是有节奏的,节奏使舞蹈的每个动作更加协调和连贯; 视图刷新也是如此,Choreographer 可以接收系统的 VSYNC 信号
Choreographer 和 Vsync 共同解决生产者何时生产,消费者何时消费的问题
因此需要一个「协调者」来协调这个工作。 Android 这里的协调者就是 Choreographer——a person who composes the sequence of steps and moves for a performance of dance. Choreographer 协调生产者什么时候去生产——也就是什么时候去绘制一帧。既然要协调,那么肯定是需要有一个协调的依据,这个依据就是 Vsync 信号——也就是垂直同步信号
具体来说是 Vsync_app
Android 4.2 (Jelly Bean)
增加检测过度绘制工具,开发者模式打开检查开关之后,可以通过不同颜色反应过度绘制的程度
Android 5.0 (Lollipop)
RenderThread
最初的 Android 版本里面是没有渲染线程的,渲染工作都是在主线程完成,使用的也都是 CPU ,调用的是 libSkia 这个库, Android5.0之后,进一步提升渲染性能。所有的GL 命令执行都放到单独线程RenderThread(渲染线程)「中,仅与GPU对话,渲染线程在 RenderNode 中存有染顿的所有信息,可以做些属性动画,这样即便主线程有耗时操作的时候也可以保证动画流程。 是当UI开启硬件加速后,用于分担主线程绘制任务的渲染线程,主线程的 draw 函数并没有真正的执行 drawCall ,而是把要 draw 的内容记录到」** DIsplayList 里面,同步到 RenderThread **中,一旦同步完成,主线程就可以被释放出来做其他的事情,RenderThread 则继续进行渲染工作
Android 7.0 (Nougat)
支持Vulkan
GL的替代品
Android 8.0 (Oreo)
Bitmap内存转移至native内存
- 2.3之前的像素存储需要的内存是在native上分配的,并且生命周期不太可控,可能需要用户自己回收。
- 2.3-7.1之间,Bitmap的像素存储在Dalvik的Java堆上,
- 4.4之前的甚至能在匿名共享内存上分配(Fresco采用),
- 8.0之后的像素内存又重新回到native上去分配,「不需要用户主动回收」,8.0之后图像资源的管理更加优秀,极大降低了OOM
NativeAllocationRegistry是Android 8.0引入的一种辅助自动回收native内存的一种机制,当Java对象因为GC被回收后,NativeAllocationRegistry可以辅助回收Java对象所申请的native内存
Android 学习笔录
Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap
相关文章:

Android渲染系列之原理概述篇
屏幕硬件 渲染离不开屏幕,Android中的屏幕碎片化比较严重,尺寸大小不一,材质也是屏幕重要的因素。 目前智能手机主流的屏幕可分为两大类即液晶显示器; LCD (Liquid Crystal Display) 液晶显示器OLED (Organic Light Emitting Diode…...

类图 UML从入门到放弃系列之二
1.劝退说明(开个玩笑) UML包含有许多小组件、修饰符以及其他小巧复杂的东西。UML的内容相当庞大,以至于你可以花大量的时间把自己修成一个UML语言律师,并能够完成所有律师能够完成的工作:编写出所有人都无法理解的文档。现在流行的敏捷开发倡…...

诊断用抗原抗体——博迈伦
抗原抗体诊断是一种常见的临床诊断方法,它通过检测人体内特定抗原或抗体的存在来确定某种疾病或感染的存在与否。这种诊断方法可以用于许多不同的疾病和感染的检测,如传染病、自身免疫病、肿瘤等。 抗原抗体诊断的原理是基于抗原与抗体之间的特异性反应。…...

156 - Ananagrams (UVA)
题目链接如下: Online Judge 我的代码如下: #include <iostream> #include <string> #include <vector> #include <map> #include <algorithm> // #define debugint main(){#ifdef debugfreopen("0.txt", &q…...

vue3入门
一. Vue3的优势 二. 使用create-vue搭建Vue3项目 2.1 认识create-vue create-vue是Vue官方新的脚手架工具,底层切换到了 vite (下一代前端工具链),为开发提供极速响应 2.2 使用create-vue创建项目 前置条件 - 已安装16.0或更高版…...

上机实验二 设计单循环链表 西安石油大学数据结构
实验名称:设计单循环链表 (1)实验目的:掌握线性表的链式存储结构;掌握单循环链表及其基本操作的实现。 (2)主要内容:实现单循环链表的初始化、求数据元素个数、插入、删除、取数据元素等操作;用插入法建立带头结点的单循环链表;设计一个测试主函数验证…...

小谈设计模式(28)—解释器模式
小谈设计模式(28)—解释器模式 专栏介绍专栏地址专栏介绍 解释器模式角色分析抽象表达式(Abstract Expression)终结符表达式(Terminal Expression)非终结符表达式(Non-terminal Expression&…...

Access denied for user ‘root‘@‘xxx‘ (using password: YES)
Access denied for user rootxxx (using password: YES) 这表示MySQL服务端拒绝来自xxx主机的root用户登录,尽管我检查了一下,root的用户名和密码都没错,还是拒绝。 解决方案: select user,host from mysql.user; 执行发现&am…...

对象与成员函数指针 function+bind
functionbind的理解 function模板类的构造函数,把对象与成员函数绑定,重载了(),利用对象调用成员函数 bind模板函数,把对象与成员函数绑定,返回function对象,成员函数传参代码链接点…...

如何在 PyTorch 中冻结模型权重以进行迁移学习:分步教程
一、说明 迁移学习是一种机器学习技术,其中预先训练的模型适用于新的但类似的问题。迁移学习的关键步骤之一是能够冻结预训练模型的层,以便在训练期间仅更新网络的某些部分。当您想要保留预训练模型已经学习的特征时,冻结至关重要。在本教程中…...

代码随想录算法训练营第六十二、六十三天 | 单调栈 part 2 | 503.下一个更大元素II 、42. 接雨水、84.柱状图中最大的矩形
目录 503.下一个更大元素II思路代码 42. 接雨水思路一 双指针思路二 单调栈代码 84.柱状图中最大的矩形思路一 双指针思路二 单调栈代码 503.下一个更大元素II Leetcode 思路 将数组乘2来遍历即可,就是加长版的每日温度。 但是处理起来会有细节,如果…...

c#设计模式-行为型模式 之 迭代器模式
🚀简介 提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 迭代器模式主要包含以下角色: 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口…...

SSM整合RabbitMQ,Spring4.x整合RabbitMQ
SSM整合RabbitMQ目录 前言版本实现目录参考pom.xml依赖rabbitmq.properties配置文件spring-rabbitmq.xmlspring-mvc.xml或applicationContext.xmlrabbitmq目录下MessageConsumer.javaMessageConsumer2.javaMessageProducer.javaMessageConstant.java 测试调用 扩展消息重发方式…...

【2023研电赛】商业计划书赛道上海市一等奖:基于双矢量优化谐波预测控制的MMC-PET光伏储能系统
该作品参与极术社区组织的2023研电赛作品征集活动,欢迎同学们投稿,获取作品传播推广,并有丰富礼品哦~ 团队介绍 参赛单位:上海理工大学 参赛队伍:Dream explorers 参赛队员:吕哲 李天皓 赵安杰 项目意义…...

minio桶命名规则
一、背景 今天做项目需要上传图片到minio,上传失败,查看错误是桶未创建成功。 minio桶的创建具有自己的命名规则,不符合则无法创建。 二、命名规则 1、存储桶名称的长度必须介于 3(最小)到 63(最大&…...

【教学类-35-04】学号+姓名+班级(中3班)学号字帖(A4竖版2份 竖版长条)
图片展示: 背景需求: 2022年9-2023年1月我去过小3班带班,但是没有在这个班级投放过学具,本周五是我在本学期第一次带中3班,所以提供了一套学号描字帖。先让我把孩子的名字和脸混个眼熟。 之前试过一页两套名字的纸张切割方法有:…...

什么叫AI自动直播?
AI自动直播是一种使用人工智能技术进行自动直播的程序或系统。 它可以自动录制视频,并在直播平台上进行展示,以吸引观众并提高品牌知名度。AI自动直播通常需要使用特定的软件或平台来实现,并且需要具备一定的编程和人工智能知识。 AI自动直…...

LLaMA Adapter和LLaMA Adapter V2
LLaMA Adapter论文地址: https://arxiv.org/pdf/2303.16199.pdf LLaMA Adapter V2论文地址: https://arxiv.org/pdf/2304.15010.pdf LLaMA Adapter效果展示地址: LLaMA Adapter 双语多模态通用模型 为你写诗 - 知乎 LLaMA Adapter GitH…...

高压放大器在软体机器人领域的应用
软体机器人是一种新型机器人技术,与传统的硬体机器人有着很大的不同。软体机器人通常由柔软的材料制成,具有高度的柔韧性和灵活性,并且可以实现多种形状和动作。但是,软体机器人的发展面临很多技术挑战,其中之一就是控…...

《Linux C/C++服务器开发实践》之第4章 TCP服务器编程
《Linux C/C服务器开发实践》之第4章 TCP服务器编程 4.1 套接字的基本概念4.2 网络程序的架构4.3 IP地址的格式转换4.1.c 4.4 套接字的类型4.5 套接字地址4.5.1 通用socket地址4.5.2 专用socket地址4.5.3 获取套接字地址4.2.c 4.6 主机字节序和网络字节序4.3.c 4.7 协议族和地址…...

HCIA---静态路由扩展配置
静态的扩展配置: 1、负载均衡:当访问相同目标,具有多条开销相似路径时;可以让设备将流量拆分后延多条路径同时传输;起到带宽叠加的作用; 2、环回接口-- 创建后,可用于路由器测试TCP/IP协议组件…...

OCP Java17 SE Developers 复习题04
答案 F. Line 5 does not compile. This question is checking to see whether you are paying attention to the types. numFish is an int, and 1 is an int. Therefore, we use numeric addition and get 5. The problem is that we cant store an int in a String variab…...

spark中使用flatmap报错:TypeError: ‘int‘ object is not subscriptable
1、背景描述 菜鸟笔者在运行下面代码时发生了报错: from pyspark import SparkContextsc SparkContext("local", "apple1012")rdd sc.parallelize([[1, 2], 3, [7, 5, 6]])rdd1 rdd.flatMap(lambda x: x) print(rdd1.collect())报错描述如…...

node.js知识系列(5)-每天了解一点
目录 21. RESTful API 设计中的 HTTP 动词22. 中间件链和回调地狱23. Express.js 的 ORM 经验24. 错误处理中间件和 HTTP 状态码25. 事件循环(Event Loop)在异步编程中的作用26. Node.js 缓存机制27. Node.js 全局对象28. 性能分析和调优经验29. Express…...

Linux服务器(银河麒麟、CentOS 7+、CentOS 7+ 等)修改IP地址
打开终端或控制台,以root或具有sudo权限的用户身份登录。根据你的Linux发行版和网络管理工具的不同,相应的命令可能略有不同。使用以下命令编辑网络配置文件,例如eth0网卡的配置文件: 注意:ifcfg-eth0 可能会有不同的命…...

Mall脚手架总结(四) —— SpringBoot整合RabbitMQ实现超时订单处理
前言 在电商项目中,订单因为某种特殊情况被取消或者超时未支付都是比较常规的用户行为,而实现该功能我们就要借助消息中间件来为我们维护这么一个消息队列。在mall脚手架中选择了RabbitMQ消息中间件,接下来荔枝就会根据功能需求来梳理一下超时…...

python实现图像的直方图均衡化
直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过重新分配图像中的像素值,使得图像的像素值分布更加均匀,增强图像的对比度,从而改善图像的视觉效果。 直方图均衡化的过程如下: 灰度转换:如果图像是彩色…...

哪种烧录单片机的方法合适?
哪种烧录单片机的方法合适? 首先,让我们来探讨一下单片机烧录的方式。虽然单片机烧录程序的具体方法会因为单片机型号、然后很多小伙伴私我想要嵌入式资料,通宵总结整理后,我十年的经验和入门到高级的学习资料,只需一…...

安规电容总结
安规电容 顾名思义:电容即使失效后,也不会漏电或者放电伤人,要符合安全规定 多数高压认证产品都需要。 上图: X电容: Y电容: 区别: 电路示意:...

MyCat分片垂直拆分
场景 在业务系统中 , 涉及以下表结构 , 但是由于用户与订单每天都会产生大量的数据 , 单台服务器的数据 存储及处理能力是有限的 , 可以对数据库表进行拆分 , 原有的数据库表如下。 现在考虑将其进行垂直分库操作,将商品相关的表拆分到一个数据库服务器&#…...