OpenHarmony实战开发-提升应用响应速度。

应用对用户的输入需要快速反馈,以提升交互体验,因此本文提供了以下方法来提升应用响应速度。

  • 避免主线程被非UI任务阻塞
  • 减少组件刷新的数量

避免主线程被非UI任务阻塞

在应用响应用户输入期间,应用主线程应尽可能只执行UI任务(待显示数据的准备、可见视图组件的更新等),非UI的耗时任务(长时间加载的内容等)建议通过异步任务延迟处理或者分配到其他线程处理。

使用组件异步加载特性

当前系统提供的Image组件默认生效异步加载特性,当应用在页面上展示一批本地图片的时候,会先显示空白占位块,当图片在其他线程加载完毕后,再替换占位块。这样图片加载就可以不阻塞页面的显示,给用户带来良好的交互体验。因此,只在加载图片耗时比较短的情况下建议下述代码。

@Entry
@Component
struct ImageExample1 {build() {Column() {Row() {Image('resources/base/media/sss001.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')Image('resources/base/media/sss002.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')Image('resources/base/media/sss003.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')Image('resources/base/media/sss004.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%')}// 此处省略若干个Row容器,每个容器内都包含如上的若干Image组件}}
}

建议:在加载图片的耗时比较短的时候,通过异步加载的效果会大打折扣,建议配置Image的syncLoad属性。

@Entry
@Component
struct ImageExample2 {build() {Column() {Row() {Image('resources/base/media/sss001.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)Image('resources/base/media/sss002.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)Image('resources/base/media/sss003.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)Image('resources/base/media/sss004.jpg').border({ width: 1 }).borderStyle(BorderStyle.Dashed).aspectRatio(1).width('25%').height('12.5%').syncLoad(true)}// 此处省略若干个Row容器,每个容器内都包含如上的若干Image组件}}
}

使用TaskPool线程池异步处理

当前系统提供了TaskPool线程池,相比worker线程,TaskPool提供了任务优先级设置、线程池自动管理机制,示例如下:

import taskpool from '@ohos.taskpool';@Concurrent
function computeTask(arr: string[]): string[] {// 模拟一个计算密集型任务let count = 0;while (count < 100000000) {count++;}return arr.reverse();
}@Entry
@Component
struct AspectRatioExample3 {@State children: string[] = ['1', '2', '3', '4', '5', '6'];aboutToAppear() {this.computeTaskInTaskPool();}async computeTaskInTaskPool() {const param = this.children.slice();let task = new taskpool.Task(computeTask, param);await taskpool.execute(task);}build() {// 组件布局}
}

创建异步任务

以下代码展示了将一个长时间执行的非UI任务通过Promise声明成异步任务,主线程可以先进行用户反馈-绘制初始页面。等主线程空闲时,再执行异步任务。等到异步任务运行完毕后,重绘相关组件刷新页面。

@Entry
@Component
struct AspectRatioExample4 {@State private children: string[] = ['1', '2', '3', '4', '5', '6'];private count: number = 0;aboutToAppear() {this.computeTaskAsync();  // 调用异步运算函数}// 模拟一个计算密集型任务computeTask() {this.count = 0;while (this.count < 100000000) {this.count++;}this.children = this.children.reverse();}computeTaskAsync() {setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行this.computeTask();}, 1000)}build() {// 组件布局}
}

减少刷新的组件数量

应用刷新页面时需要尽可能减少刷新的组件数量,如果数量过多会导致主线程执行测量、布局的耗时过长,还会在自定义组件新建和销毁过程中,多次调用aboutToAppear()、aboutToDisappear()方法,增加主线程负载。

使用容器限制刷新范围

反例:如果容器内有组件被if条件包含,if条件结果变更会触发创建和销毁该组件,如果此时影响到容器的布局,该容器内所有组件都会刷新,导致主线程UI刷新耗时过长。

以下代码的Text(‘New Page’)组件被状态变量isVisible控制,isVisible为true时创建,false时销毁。当isVisible发生变化时,Stack容器内的所有组件都会刷新:

@Entry
@Component
struct StackExample5 {@State isVisible : boolean = false;build() {Column() {Stack({alignContent: Alignment.Top}) {Text().width('100%').height('70%').backgroundColor(0xd2cab3).align(Alignment.Center).textAlign(TextAlign.Center);// 此处省略100个相同的背景Text组件if (this.isVisible) {Text('New Page').height("100%").height("70%").backgroundColor(0xd2cab3).align(Alignment.Center).textAlign(TextAlign.Center);}}Button("press").onClick(() => {this.isVisible = !(this.isVisible);})}}
}

建议:对于这种受状态变量控制的组件,在if外套一层容器,减少刷新范围。

@Entry
@Component
struct StackExample6 {@State isVisible : boolean = false;build() {Column() {Stack({alignContent: Alignment.Top}) {Text().width('100%').height('70%').backgroundColor(0xd2cab3).align(Alignment.Center).textAlign(TextAlign.Center);// 此处省略100个相同的背景Text组件Stack() {if (this.isVisible) {Text('New Page').height("100%").height("70%").backgroundColor(0xd2cab3).align(Alignment.Center).textAlign(TextAlign.Center);}}.width('100%').height('70%')}Button("press").onClick(() => {this.isVisible = !(this.isVisible);})}}
}

按需加载列表组件的元素

反例:this.arr中的每一项元素都被初始化和加载,数组中的元素有10000个,主线程执行耗时长。

@Entry
@Component
struct MyComponent7 {@State arr: number[] = Array.from(Array<number>(10000), (v,k) =>k); build() {List() {ForEach(this.arr, (item: number) => {ListItem() {Text(`item value: ${item}`)}}, (item: number) => item.toString())}}
}

建议:这种情况下用LazyForEach替换ForEach,LazyForEach一般只加载可见的元素,避免一次性初始化和加载所有元素。

class BasicDataSource implements IDataSource {private listeners: DataChangeListener[] = []public totalCount(): number {return 0}public getData(index: number): string {return ''}registerDataChangeListener(listener: DataChangeListener): void {if (this.listeners.indexOf(listener) < 0) {console.info('add listener')this.listeners.push(listener)}}unregisterDataChangeListener(listener: DataChangeListener): void {const pos = this.listeners.indexOf(listener);if (pos >= 0) {console.info('remove listener')this.listeners.splice(pos, 1)}}notifyDataReload(): void {this.listeners.forEach(listener => {listener.onDataReloaded()})}notifyDataAdd(index: number): void {this.listeners.forEach(listener => {listener.onDataAdd(index)})}notifyDataChange(index: number): void {this.listeners.forEach(listener => {listener.onDataChange(index)})}notifyDataDelete(index: number): void {this.listeners.forEach(listener => {listener.onDataDelete(index)})}notifyDataMove(from: number, to: number): void {this.listeners.forEach(listener => {listener.onDataMove(from, to)})}
}class MyDataSource extends BasicDataSource {private dataArray: string[] = Array.from(Array<number>(10000), (v, k) => k.toString());public totalCount(): number {return this.dataArray.length}public getData(index: number): string  {return this.dataArray[index]}public addData(index: number, data: string): void {this.dataArray.splice(index, 0, data)this.notifyDataAdd(index)}public pushData(data: string): void {this.dataArray.push(data)this.notifyDataAdd(this.dataArray.length - 1)}
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource()build() {List() {LazyForEach(this.data, (item: string) => {ListItem() {Text(item).fontSize(20).margin({ left: 10 })}}, (item:string) => item)}}
}

合理使用缓存提升响应速度

缓存可以存储经常访问的数据或资源,当下次需要访问相同数据时,可以直接从缓存中获取,避免了重复的计算或请求,从而加快了响应速度。

使用AVPlayer实例缓存提升视频加载速度

AVPlayer实例的创建与销毁都很消耗性能,针对这个问题可以使用实例缓存进行优化,首次加载页面时创建两个实例,在打开新页面时切换空闲实例,通过reset方法重置实例到初始化状态。优化点在于不需要频繁创建销毁实例,且reset方法性能优于release方法。下面以AVPlayer为例列出正反例对比供参考。

反例:打开新页面时创建实例,离开页面时使用release方法销毁实例。

import media from '@ohos.multimedia.media';@Entry
@Component
struct Index {private avPlayer: media.AVPlayer | undefined = undefined;aboutToAppear(): void {// 页面创建时初始化AVPlayer实例media.createAVPlayer().then((ret) => {this.avPlayer = ret;});}aboutToDisappear(): void {// 离开页面时销毁AVPlayer实例if (this.avPlayer) {this.avPlayer.release();}this.avPlayer = undefined;}build() {// 组件布局}
}

正例:首次加载页面时维护两个实例,在切换页面时切换实例,并将之前的实例通过reset方法重置。

import media from '@ohos.multimedia.media';@Entry
@Component
struct Index {private avPlayer: media.AVPlayer | undefined = undefined;private avPlayerManager: AVPlayerManager = AVPlayerManager.getInstance();aboutToAppear(): void {this.avPlayerManager.switchPlayer();this.avPlayer = this.avPlayerManager.getCurrentPlayer();}aboutToDisappear(): void {this.avPlayerManager.resetCurrentPlayer();this.avPlayer = undefined;}build() {// 组件布局}
}class AVPlayerManager {private static instance?: AVPlayerManager;private player1?: media.AVPlayer;private player2?: media.AVPlayer;private currentPlayer?: media.AVPlayer;public static getInstance(): AVPlayerManager {if (!AVPlayerManager.instance) {AVPlayerManager.instance = new AVPlayerManager();}return AVPlayerManager.instance;}async AVPlayerManager() {this.player1 = await media.createAVPlayer();this.player2 = await media.createAVPlayer();}/*** 切换页面时切换AVPlayer实例*/switchPlayer(): void {if (this.currentPlayer === this.player1) {this.currentPlayer = this.player2;} else {this.currentPlayer = this.player1;}}getCurrentPlayer(): media.AVPlayer | undefined {return this.currentPlayer;}/*** 使用reset方法重置AVPlayer实例*/resetCurrentPlayer(): void {this.currentPlayer?.pause(() => {this.currentPlayer?.reset();});}
}

合理使用预加载提升响应速度

使用NodeContainer提前渲染降低响应时延

应用启动时有广告页的场景下。如果先渲染广告页而后再渲染首页,很可能造成首页响应时延较长,影响用户体验。针对此类问题可以使用NodeContainer在广告页渲染时同步渲染首页,等到跳转到首页时直接送显,提高响应速度。

反例:按次序依次渲染送显

主要代码逻辑如下:

1、模拟广告页,通过点击不同按钮分别进入普通页面和预加载页面

// Index.etsimport router from '@ohos.router';@Entry
@Component
struct Index {build() {Column({ space: 5 }) {// 进入普通页面Button("普通页面").type(ButtonType.Capsule).onClick(() => {router.pushUrl({ url: 'pages/CommonPage' })})// 进入预加载页面Button("预加载页面").type(ButtonType.Capsule).onClick(() => {router.pushUrl({ url: 'pages/PreloadedPage' })})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}

2、普通首页,也即按顺序普通渲染的页面

// CommonPage.etsimport { MyBuilder, getNumbers } from '../builder/CustomerBuilder';@Entry
@Component
struct CommonPage {build() {Row() {MyBuilder(getNumbers())}}
}

3、自定义builder,用来定制页面结构

// CustomerBuilder.ets@Builder
export function MyBuilder(numbers: string[]) {Column() {List({ space: 20, initialIndex: 0 }) {ForEach(numbers, (item: string) => {ListItem() {Text('' + item).width('100%').height(50).fontSize(16).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)}}, (day: string) => day)}.listDirection(Axis.Vertical) // 排列方向.scrollBar(BarState.Off).friction(0.6).divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线.edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring.width('90%').height('100%')}.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
}export const getNumbers = (): string[] => {const numbers: string[] = [];for (let i = 0; i < 100; i++) {numbers.push('' + i)}return numbers;
}

正例:在启动时预加载首页

主要代码逻辑如下:

1、应用启动时提前创建首页

// EntryAbility.ets  import { ControllerManager } from '../builder/CustomerController';
import { getNumbers } from '../builder/CustomerBuilder';export default class EntryAbility extends UIAbility {onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');windowStage.loadContent('pages/Index', (err, data) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');});window.getLastWindow(this.context, (err: BusinessError, data) => {if (err.code) {console.error('Failed to obtain top window. Cause:' + JSON.stringify(err));return;}// 提前创建ControllerManager.getInstance().createNode(data.getUIContext(), getNumbers());})}onWindowStageDestroy(): void {// Main window is destroyed, release UI related resourceshilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');// 清空组件,防止内存泄漏ControllerManager.getInstance().clearNode();}
}

2、预加载的首页,使用NodeContainer进行占位,当跳转到本页时直接将提前创建完成的首页填充

// PreloadedPage.etsimport { ControllerManager } from '../builder/CustomerController';@Entry
@Component
struct PreloadedPage {build() {Row() {NodeContainer(ControllerManager.getInstance().getNode())}}
}

3、自定义NodeController,并提供提前创建首页的能力

// CustomerController.etsimport { UIContext } from '@ohos.arkui.UIContext';
import { NodeController, BuilderNode, FrameNode } from "@ohos.arkui.node";
import { MyBuilder } from './CustomerBuilder';export class MyNodeController extends NodeController {private rootNode: BuilderNode<[string[]]> | null = null;private wrapBuilder: WrappedBuilder<[string[]]> = wrapBuilder(MyBuilder);private numbers: string[] | null = null;constructor(numbers: string[]) {super();this.numbers = numbers;}makeNode(uiContext: UIContext): FrameNode | null {if (this.rootNode != null) {// 返回FrameNode节点return this.rootNode.getFrameNode();}// 返回null控制动态组件脱离绑定节点return null;}// 通过UIContext初始化BuilderNode,再通过BuilderNode中的build接口初始化@Builder中的内容initNode(uiContext: UIContext) {if (this.rootNode != null) {return;}// 创建节点,需要uiContextthis.rootNode = new BuilderNode(uiContext)// 创建组件this.rootNode.build(this.wrapBuilder, this.numbers)}
}export class ControllerManager {private static instance?: ControllerManager;private myNodeController?: MyNodeController;static getInstance(): ControllerManager {if (!ControllerManager.instance) {ControllerManager.instance = new ControllerManager();}return ControllerManager.instance;}/*** 初始化需要UIContext 需在Ability获取* @param uiContext* @param numbers*/createNode(uiContext: UIContext, numbers: string[]) {// 创建NodeControllerthis.myNodeController = new MyNodeController(numbers);this.myNodeController.initNode(uiContext);}/*** 自定义获取NodeController实例接口* @returns MyNodeController*/getNode(): MyNodeController | undefined {return this.myNodeController;}/*** 解除占用,防止内存泄漏*/clearNode(): void {this.myNodeController = undefined;}
}

通过SmartPerf-Host工具抓取相关trace进行分析首页响应时延,其中主要关注两个trace tag分别是DispatchTouchEvent代表点击事件和MarshRSTransactionData代表响应,如下图所示:

反例响应时延:18.1ms
在这里插入图片描述

正例响应时延:9.4ms
在这里插入图片描述

由上述对比数据即可得出结论,预加载首页能优化首页响应时延。

如果大家还没有掌握鸿蒙,现在想要在最短的时间里吃透它,我这边特意整理了《鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程》以及《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

OpenHarmony APP开发教程步骤:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

《鸿蒙开发学习手册》:

如何快速入门:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.基本概念
2.构建第一个ArkTS应用
3.……

在这里插入图片描述

开发基础知识:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙生态应用开发白皮书V2.0PDF:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【电控笔记6.3】采样-Z转换-零阶保持器

本质 数字转模拟:零阶保持器 采样 z-1所描述的物理意义即为延迟T时间的拉氏转换e-sT 信号采样延时

Python --- 新手小白自己动手安装Anaconda+Jupyter Notebook全记录(Windows平台)

新手小白自己动手安装AnacondaJupyter Notebook全记录 这两天在家学Pythonmathine learning&#xff0c;在我刚刚入手python的时候&#xff0c;我写了一篇新手的入手文章&#xff0c;是基于Vs code编译器的入手指南&#xff0c;里面包括如何安装python&#xff0c;以及如何在Vs…

【通信原理笔记】【四】数字基带传输——4.1 数字基带信号

文章目录 前言一、数字信号二、数字基带信号波形2.1 码元波形2.2 相对码2.3 多电平码 总结 前言 从这一节开始介绍数字通信系统中的数字基带传输部分。与模拟通信系统相比&#xff0c;数字通信系统传输的对象是数字的离散信号而非连续的模拟信号&#xff0c;本节先学习什么是数…

在传统云安全失败时提供帮助的六种策略

随着基于内存的攻击的激增继续挑战传统的云安全防御&#xff0c;对主动和全面的安全措施的需求变得至关重要。采用结合端点检测和响应、内存完整性保护和定期更新的多层方法可以加强对这些难以捉摸的威胁的防御。 随着云计算技术在各行各业的迅速普及&#xff0c;数据保护和安全…

linux系统安全与应用【下】

目录 1.开关机安全控制 1.1GRUB限制 2.终端登录安全控制 2.1 限制root只在安全终端登录 2.2 禁止普通用户登录 3.弱口令检测 3.1 Joth the Ripper&#xff08;JR&#xff09; 4.网络端口扫描 4.1 nmap命令 1.开关机安全控制 1.1GRUB限制 通常情况下在系统开机进入GRU…

详解:老阳说的temu电商项目怎么做才更赚钱?

近年来&#xff0c;电商行业蓬勃发展&#xff0c;temu电商项目作为其中的一员&#xff0c;也受到了广泛关注。老阳作为行业内的资深人士&#xff0c;对于temu电商项目有着独到的见解。那么&#xff0c;如何才能做好temu电商项目呢? 首先&#xff0c;要明确temu电商项目的定位和…

Day39 网络编程(一):计算机网络,网络编程,网络模型,网络编程三要素

Day39 网络编程&#xff08;一&#xff09;&#xff1a;计算机网络&#xff0c;网络编程&#xff0c;网络模型&#xff0c;网络编程三要素 文章目录 Day39 网络编程&#xff08;一&#xff09;&#xff1a;计算机网络&#xff0c;网络编程&#xff0c;网络模型&#xff0c;网络…

day07 51单片机-串口通信

51 单片机-串口通信 1 串口通信 1.1 需求描述 本案例讲解如何通过串口和PC以9600波特率,无校验位、1停止位通信。最终实现PC向单片机发送字符串,单片机回复PC。本案例中采用串口1通信。 1.2 硬件设计 1.2.1 串口工作原理 串口是将数据按照比特逐一发送的通信接口。在串…

Python 开发实现登陆和注册模块

Python 开发实现登陆和注册模块 一、案例介绍 本例设计一个用户登录和注册模块&#xff0c;使用Tkinter框架构建界面&#xff0c;主要用到画布、文本框、按钮等组件。涉及知识点&#xff1a;Python Tkinter界面编程、pickle数据存储。本例实现了基本的用户登录和注册互动界面…

web前端 html5+css3相关知识点(跟着黑马学)8

先总结一下网页常见的布局方式&#xff1a; 1. 标准流 块级元素独占一行 -> 垂直布局 行内元素/行内块元素一行显示多个 -> 水平布局 2. 浮动 可以让原本垂直布局的块级元素变成水平布局。 3. 定位 可以让元素自由的摆放在网页的任意位置 一般用于盒子之间的层叠…

分布式锁(Redis)

一、序言 本文和大家聊聊分布式锁以及常见的解决方案。 二、什么是分布式锁 假设一个场景&#xff1a;一个库存服务部署在上面三台机器上&#xff0c;数据库里有 100 件库存&#xff0c;现有 300 个客户同时下单。并且这 300 个客户均摊到上面的三台机器上&#xff08;即三台…

React 19 带来了 JSX 运行时的重要更新

在 React 的发展历程中&#xff0c;JSX 运行时一直扮演着重要的角色。在以前的的版本&#xff0c;JSX 运行时会克隆传入的 props 对象&#xff0c;这背后有着两大原因。 历史原因 React 保留了一些特殊的 prop 名称&#xff0c;如 key 和在 React 19 之前的 ref。这些 prop 并…

SpringBoot整合Swagger3生成接口文档

一&#xff1a;前言 Swagger 是一个 RESTful API 的开源框架&#xff0c;它的主要目的是帮助开发者设计、构建、文档化和测试 Web API。Swagger 的核心思想是通过定义和描述 API 的规范、结构和交互方式&#xff0c;以提高 API 的可读性、可靠性和易用性&#xff0c;同时降低 …

深度图转点云

一、理论分析 二、其他分析 1、相机内参 相机内参主要是四个参数fx,fy,u0,v0。要明白相机内参就是相机内部参数&#xff0c;是参考像素坐标系而言&#xff0c;有了这个前提&#xff0c;这四个参数也就很好理解了。 &#xff08;1&#xff09;首先&#xff0c;。其中F是相机的…

Oracle中的 plsql语法

01-plsql 为什么要plsql 复杂的业务逻辑 可以使用 编程语言实现 sql无法实现 plsql也可以实现复杂的业务逻辑 为不直接使用编程语言 而是学习plsql plsql会比直接使用 编程语言 速度更快 基本语法&#xff1a; [declare --声明变量 变量名 变量类型 ] begin --代码逻辑 …

Springboot Gateway 报错Failed to resolve “bogon”的原因及解决办法

一、问题出现原因及初步分析 今天遇到一个奇怪的错误&#xff0c;一个一直正确运行的微服务后台&#xff0c;突然无法访问&#xff0c;如何重启都会报错。 想到近期有人在服务器上安装过其它服务&#xff0c;因此&#xff0c;考虑可能是配置问题&#xff0c;可配置问题修复后…

1.基于Springboot对SpringEvent初步封装

一&#xff1a;前置知识 Spring Event是Spring框架提供的一种事件机制&#xff0c;用于处理组件之间的通信。在复杂的系统中&#xff0c;模块或组件之间的通信是必不可少的。Spring Event可以用于以下场景&#xff1a; 1.系统间解耦&#xff1a;模块或组件之间通过事件进行通…

账号安全基本措施1

一、系统账号清理 1.1 将用户设置为无法登录 useradd -s /sbin/nologin lisi shell类型设置为/sbin/nologin用户将无法使用bash或其他shell来登录系统。 1.2 锁定用户。passwd -l 用户名 正常情况下是可以送普通用户切换到其他普通用户的 当锁定密码后passwd -l lisi就用普…

LeetCode:组合求和III之回溯法

题目 题目链接 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a;只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。题目图解 ** ** cpp代码 class …

AI预测体彩排列3第2套算法实战化测试第1弹2024年4月22日第1次测试

从今天开始&#xff0c;开始新一轮的测试&#xff0c;本轮测试&#xff0c;以6码为基础&#xff0c;同步测试杀号情况&#xff0c;争取杀至4-5码。经过计算&#xff0c;假如5码命中&#xff0c;即每期125注&#xff0c;投入250元&#xff0c;十期共计2500元&#xff0c;则命中率…