9种单片机常用的软件架构

长文预警,加代码5000多字,写了4个多小时,盘软件架构,这篇文章就够了!

可能很多工程师,工作了很多年,都不会有软件架构的概念。

因为我在做研发工程师的第6年,才开始意识到这个东西,在此之前,都是做一些比较简单的项目,一个main函数干到底,架构复杂了反而是累赘。

后面有幸,接触了稍微复杂点的项目,感觉以前水平Hold不住,然后借着项目需求,学习了很多优秀的代码架构,比如以前同事的,一些模组厂的SDK,还有市面上成熟的系统。

说出来可能有点夸张,一个好项目带来的成长,顶你做几年小项目。

在一个工程师从入门到成为高级工程师,都会经历哪些软件架构?

下面给大家盘点一下,每个都提供了简易的架构模型代码。

1.线性架构

这是最简单的一种程序设计方法,也就是我们在入门时写的,下面是一个使用C语言编写的线性架构示例:

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 延时函数,用于产生一定的延迟
void delay(unsigned int count) {unsigned int i;while(count--) {for(i = 0; i < 120; i++) {}  // 空循环,用于产生延迟}
}void main() {// 初始设置P1端口为输出模式,用于控制LEDP1 = 0xFF;  // 将P1端口设置为高电平,关闭所有LEDwhile(1) {  // 无限循环P1 = 0x00;  // 将P1端口设置为低电平,点亮所有LEDdelay(500000);  // 调用延时函数,延迟一段时间P1 = 0xFF;  // 将P1端口设置为高电平,关闭所有LEDdelay(500000);  // 再次调用延时函数,延迟相同的时间}
}

2.模块化架构

模块化架构是一种将程序分解为独立模块的设计方法,每个模块执行特定的任务。

这种架构有助于代码的重用、维护和测试。

下面是一个使用C语言编写的模块化架构示例,该程序模拟了一个简单的交通信号灯控制系统。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 定义信号灯的状态
typedef enum {RED_LIGHT,YELLOW_LIGHT,GREEN_LIGHT
} TrafficLightState;// 函数声明
void initializeTrafficLight(void);
void setTrafficLight(TrafficLightState state);
void delay(unsigned int milliseconds);// 信号灯控制主函数
void main(void) {initializeTrafficLight();  // 初始化交通信号灯while(1) {setTrafficLight(RED_LIGHT);delay(5000);  // 红灯亮5秒setTrafficLight(YELLOW_LIGHT);delay(2000);  // 黄灯亮2秒setTrafficLight(GREEN_LIGHT);delay(5000);  // 绿灯亮5秒}
}// 初始化交通信号灯的函数
void initializeTrafficLight(void) {// 这里可以添加初始化代码,比如设置端口方向、默认状态等// 假设P1端口连接了信号灯,初始状态为熄灭(高电平)P1 = 0xFF;
}// 设置交通信号灯状态的函数
void setTrafficLight(TrafficLightState state) {switch(state) {case RED_LIGHT:// 设置红灯亮,其他灯灭P1 = 0b11100000;  // 假设低电平有效,这里设置P1.0为低电平,其余为高电平break;case YELLOW_LIGHT:// 设置黄灯亮,其他灯灭P1 = 0b11011000;  // 设置P1.1为低电平,其余为高电平break;case GREEN_LIGHT:// 设置绿灯亮,其他灯灭P1 = 0b11000111;  // 设置P1.2为低电平,其余为高电平break;default:// 默认为熄灭所有灯P1 = 0xFF;break;}
}// 延时函数,参数是毫秒数
void delay(unsigned int milliseconds) {unsigned int delayCount = 0;while(milliseconds--) {for(delayCount = 0; delayCount < 120; delayCount++) {// 空循环,用于产生延时}}
}

3.层次化架构

层次化架构是一种将系统分解为多个层次的设计方法,每个层次负责不同的功能。

着以下是一个使用C语言编写的层次化架构示例,模拟了一个具有不同权限级别的嵌入式系统。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 定义不同的操作级别
typedef enum {LEVEL_USER,LEVEL_ADMIN,LEVEL_SUPERUSER
} OperationLevel;// 函数声明
void systemInit(void);
void performOperation(OperationLevel level);
void displayMessage(char* message);// 系统初始化后的主循环
void main(void) {systemInit();  // 系统初始化// 模拟用户操作performOperation(LEVEL_USER);// 模拟管理员操作performOperation(LEVEL_ADMIN);// 模拟超级用户操作performOperation(LEVEL_SUPERUSER);while(1) {// 主循环可以是空闲循环或者处理其他低优先级任务}
}// 系统初始化函数
void systemInit(void) {// 初始化系统资源,如设置端口、中断等// 这里省略具体的初始化代码
}// 执行不同级别操作的函数
void performOperation(OperationLevel level) {switch(level) {case LEVEL_USER://用户操作具体代码break;case LEVEL_ADMIN://管理员操作具体代码break;case LEVEL_SUPERUSER://超级用户操作具体代码break;}
}// 显示消息的函数
void displayMessage(char* message) {// 这里省略了实际的显示代码,因为单片机通常没有直接的屏幕输出// 消息可以通过LED闪烁、串口输出或其他方式展示// 假设通过P1端口的LED展示,每个字符对应一个LED闪烁模式// 实际应用中,需要根据硬件设计来实现消息的显示
}

4.事件驱动架构

事件驱动架构是一种编程范式,其中程序的执行流程由事件(如用户输入、传感器变化、定时器到期等)触发。

在单片机开发中,事件驱动架构通常用于响应外部硬件中断或软件中断。

以下是一个使用C语言编写的事件驱动架构示例,模拟了一个基于按键输入的LED控制。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 定义按键和LED的状态
#define KEY_PORT P3  // 假设按键连接在P3端口
#define LED_PORT P2  // 假设LED连接在P2端口// 函数声明
void delay(unsigned int milliseconds);
bit checkKeyPress(void);  // 返回按键是否被按下的状态(1表示按下,0表示未按下)// 定时器初始化函数
void timer0Init(void) 
{TMOD = 0x01;  // 设置定时器模式寄存器,使用模式1(16位定时器)TH0 = 0xFC;   // 设置定时器初值,用于产生定时中断TL0 = 0x18;ET0 = 1;      // 开启定时器0中断EA = 1;       // 开启总中断TR0 = 1;      // 启动定时器
}// 定时器中断服务程序
void timer0_ISR() interrupt 1 
{// 定时器溢出后自动重新加载初值,无需手动重置// 这里可以放置定时器溢出后需要执行的代码
}// 按键中断服务程序
bit keyPress_ISR(void) interrupt 2 using 1 
{if(KEY_PORT != 0xFF) // 检测是否有按键按下{  LED_PORT = ~LED_PORT;  // 如果有按键按下,切换LED状态delay(20);  // 去抖动延时while(KEY_PORT != 0xFF);  // 等待按键释放return 1;  // 返回按键已按下}return 0;  // 如果没有按键按下,返回0
}// 延时函数,参数是毫秒数
void delay(unsigned int milliseconds) {unsigned int i, j;for(i = 0; i < milliseconds; i++)for(j = 0; j < 1200; j++);  // 空循环,用于产生延时
}// 主函数
void main(void) 
{timer0Init();  // 初始化定时器LED_PORT = 0xFF;  // 初始LED熄灭(假设低电平点亮LED)while(1) {if(checkKeyPress()){  // 检查是否有按键按下事件// 如果有按键按下,这里可以添加额外的处理代码}}
}// 检查按键是否被按下的函数
bit checkKeyPress(void) 
{bit keyState = 0;// 模拟按键中断触发,实际应用中需要连接硬件中断if(1) // 假设按键中断触发{  keyState = keyPress_ISR();  // 调用按键中断服务程序}return keyState;  // 返回按键状态
}

事实上,真正的事件型驱动架构,是非常复杂的,我职业生涯的巅峰之作,就是用的事件型驱动架构。

5.状态机架构

在单片机开发中,状态机常用于处理复杂的逻辑和事件序列,如用户界面管理、协议解析等。

以下是一个使用C语言编写的有限状态机(FSM)的示例,模拟了一个简单的自动售货机的状态转换。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 定义自动售货机的状态
typedef enum {IDLE,COIN_INSERTED,PRODUCT_SELECTED,DISPENSE,CHANGE_RETURNED
} VendingMachineState;// 定义事件
typedef enum {COIN_EVENT,PRODUCT_EVENT,DISPENSE_EVENT,REFUND_EVENT
} VendingMachineEvent;// 函数声明
void processEvent(VendingMachineEvent event);
void dispenseProduct(void);
void returnChange(void);// 当前状态
VendingMachineState currentState = IDLE;// 主函数
void main(void)
{// 初始化代码(如果有)// ...while(1){// 假设事件由外部触发,这里使用一个模拟事件VendingMachineEvent currentEvent = COIN_EVENT; // 模拟投入硬币事件processEvent(currentEvent);  // 处理当前事件}
}// 处理事件的函数
void processEvent(VendingMachineEvent event)
{switch(currentState){case IDLE:if(event == COIN_EVENT){// 如果在空闲状态且检测到硬币投入事件,则转换到硬币投入状态currentState = COIN_INSERTED;}break;case COIN_INSERTED:if(event == PRODUCT_EVENT){// 如果在硬币投入状态且用户选择商品,则请求出货currentState = PRODUCT_SELECTED;}break;case PRODUCT_SELECTED:if(event == DISPENSE_EVENT){dispenseProduct();  // 出货商品currentState = DISPENSE;}break;case DISPENSE:if(event == REFUND_EVENT){returnChange();  // 返回找零currentState = CHANGE_RETURNED;}break;case CHANGE_RETURNED:// 等待下一个循环,返回到IDLE状态currentState = IDLE;break;default:// 如果状态非法,重置为IDLE状态currentState = IDLE;break;}
}// 出货商品的函数
void dispenseProduct(void)
{// 这里添加出货逻辑,例如激活电机推出商品// 假设P1端口连接了出货电机P1 = 0x00;  // 激活电机// ... 出货逻辑P1 = 0xFF;  // 关闭电机
}// 返回找零的函数
void returnChange(void)
{// 这里添加找零逻辑,例如激活机械臂放置零钱// 假设P2端口连接了找零机械臂P2 = 0x00;  // 激活机械臂// ... 找零逻辑P2 = 0xFF;  // 关闭机械臂
}

6.面向对象架构

STM32的库,就是一种面向对象的架构。

不过在单片机由于资源限制,OOP并不像在高级语言中那样常见,但是一些基本概念如封装和抽象仍然可以被应用。

虽然C语言本身并不直接支持面向对象编程,但可以通过结构体和函数指针模拟一些面向对象的特性。

下面是一个简化的示例,展示如何在C语言中模拟面向对象的编程风格,以51单片机为背景,创建一个简单的LED类。

#include <reg51.h>// 定义一个LED类
typedef struct {unsigned char state;  // LED的状态unsigned char pin;    // LED连接的引脚void (*turnOn)(struct LED*);  // 点亮LED的方法void (*turnOff)(struct LED*); // 熄灭LED的方法
} LED;// LED类的构造函数
void LED_Init(LED* led, unsigned char pin) {led->state = 0;  // 默认状态为熄灭led->pin = pin;   // 设置LED连接的引脚
}// 点亮LED的方法
void LED_TurnOn(LED* led) {// 根据引脚状态点亮LEDif(led->pin < 8) {P0 |= (1 << led->pin);  // 假设P0.0到P0.7连接了8个LED} else {P1 &= ~(1 << (led->pin - 8));  // 假设P1.0到P1.7连接了另外8个LED}led->state = 1;  // 更新状态为点亮
}// 熄灭LED的方法
void LED_TurnOff(LED* led) {// 根据引脚状态熄灭LEDif(led->pin < 8) {P0 &= ~(1 << led->pin);  // 熄灭P0上的LED} else {P1 |= (1 << (led->pin - 8));  // 熄灭P1上的LED}led->state = 0;  // 更新状态为熄灭
}// 主函数
void main(void) {LED myLed;  // 创建一个LED对象LED_Init(&myLed, 3);  // 初始化LED对象,连接在P0.3// 给LED对象绑定方法myLed.turnOn = LED_TurnOn;myLed.turnOff = LED_TurnOff;// 使用面向对象的风格控制LEDwhile(1) {myLed.turnOn(&myLed);  // 点亮LED// 延时myLed.turnOff(&myLed); // 熄灭LED// 延时}
}

这段代码定义了一个结构体LED,模拟面向对象中的“类。

这个示例仅用于展示如何在C语言中模拟面向对象的风格,并没有使用真正的面向对象编程语言的特性,如继承和多态,不过对于单片机的应用,足以。

7.基于任务的架构

这种我最喜欢用,结构,逻辑清晰,每个任务都能灵活调度。

基于任务的架构是将程序分解为独立的任务,每个任务执行特定的工作。

在单片机开发中,如果没有使用实时操作系统,我们可以通过编写一个简单的轮询调度器来模拟基于任务的架构。

以下是一个使用C语言编写的基于任务的架构的示例,该程序在51单片机上实现。

为了简化,我们将使用一个简单的轮询调度器来在两个任务之间切换:一个是按键扫描任务,另一个是LED闪烁任务。

#include <reg51.h>// 假设P1.0是LED输出
sbit LED = P1^0;// 全局变量,用于记录系统Tick
unsigned int systemTick = 0;// 任务函数声明
void taskLEDBlink(void);
void taskKeyScan(void);// 定时器0中断服务程序,用于产生Tick
void timer0_ISR() interrupt 1 using 1 
{// 定时器溢出后自动重新加载初值,无需手动重置systemTick++;  // 更新系统Tick计数器
}// 任务调度器,主函数中调用,负责任务轮询
void taskScheduler(void) 
{// 检查系统Tick,决定是否执行任务// 例如,如果我们需要每1000个Tick执行一次LED闪烁任务if (systemTick % 1000 == 0) {taskLEDBlink();}// 如果有按键任务,可以类似地检查Tick并执行if (systemTick % 10 == 0) {taskKeyScan();}
}// LED闪烁任务
void taskLEDBlink(void) 
{static bit ledState = 0;  // 用于记录LED的当前状态ledState = !ledState;  // 切换LED状态LED = ledState;         // 更新LED硬件状态
}// 按键扫描任务(示例中省略具体实现)
void taskKeyScan(void) 
{// 按键扫描逻辑
}// 主函数
void main(void) 
{// 初始化LED状态LED = 0;// 定时器0初始化设置TMOD &= 0xF0;  // 设置定时器模式寄存器,使用模式1(16位定时器/计数器)TH0 = 0x4C;     // 设置定时器初值,产生定时中断(定时周期取决于系统时钟频率)TL0 = 0x00;ET0 = 1;        // 允许定时器0中断EA = 1;         // 允许中断TR0 = 1;        // 启动定时器0while(1) {taskScheduler();  // 调用任务调度器}
}

这里只是举个简单的例子,这个代码示例,比较适合51和stm8这种资源非常少的单片机。

8.代理架构

这个大家或许比较少听到过,但在稍微复杂的项目中,是非常常用的。

在代理架构中,每个代理(Agent)都是一个独立的实体,它封装了特定的决策逻辑和数据,并与其他代理进行交互。

在实际项目中,需要创建多个独立的任务或模块,每个模块负责特定的功能,并通过某种机制(如消息队列、事件触发等)进行通信。

这种方式可以大大提高程序可扩展性和可移植性。

以下是一个LED和按键代理的简化模型。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 假设P3.5是按键输入,P1.0是LED输出
sbit KEY = P3^5;
sbit LED = P1^0;typedef struct 
{unsigned char pin;    // 代理关联的引脚void (*action)(void); // 代理的行为函数
} Agent;// 按键代理的行为函数声明
void keyAction(void);
// LED代理的行为函数声明
void ledAction(void);// 代理数组,存储所有代理的行为和关联的引脚
Agent agents[] = 
{{5, keyAction},  // 按键代理,关联P3.5{0, ledAction}   // LED代理,关联P1.0
};// 按键代理的行为函数
void keyAction(void) 
{if(KEY == 0) // 检测按键是否被按下{  LED = !LED;   // 如果按键被按下,切换LED状态while(KEY == 0);  // 等待按键释放}
}// LED代理的行为函数
void ledAction(void) 
{static unsigned int toggleCounter = 0;toggleCounter++;if(toggleCounter == 500)  // 假设每500个时钟周期切换一次LED{ LED = !LED;               // 切换LED状态toggleCounter = 0;        // 重置计数器}
}// 主函数
void main(void) 
{unsigned char agentIndex;// 主循环while(1) {for(agentIndex = 0; agentIndex < sizeof(agents) / sizeof(agents[0]); agentIndex++) {// 调用每个代理的行为函数(*agents[agentIndex].action)(); // 注意函数指针的调用方式}}
}

9.组件化架构

组件化架构是一种将软件系统分解为独立、可重用组件的方法。

将程序分割成负责特定任务的模块,如LED控制、按键处理、传感器读数等。

每个组件可以独立开发和测试,然后被组合在一起形成完整的系统。

以下是一个简化的组件化架构示例,模拟了一个单片机系统中的LED控制和按键输入处理两个组件。

为了简化,组件间的通信将通过直接函数调用来模拟。

#include <reg51.h>  // 包含51系列单片机的寄存器定义// 定义组件结构体
typedef struct 
{void (*init)(void);      // 组件初始化函数void (*task)(void);       // 组件任务函数
} Component;// 假设P3.5是按键输入,P1.0是LED输出
sbit KEY = P3^5;
sbit LED = P1^0;// LED组件
void LED_Init(void) 
{LED = 0;  // 初始化LED状态为关闭
}void LED_Task(void) 
{static unsigned int toggleCounter = 0;toggleCounter++;if (toggleCounter >= 1000) // 假设每1000个时钟周期切换一次LED{  LED = !LED;                // 切换LED状态toggleCounter = 0;         // 重置计数器}
}// 按键组件
void KEY_Init(void) 
{// 按键初始化代码
}void KEY_Task(void) 
{if (KEY == 0) // 检测按键是否被按下{  LED = !LED;  // 如果按键被按下,切换LED状态while(KEY == 0);  // 等待按键释放}
}// 组件数组,存储系统中所有组件的初始化和任务函数
Component components[] = 
{{LED_Init, LED_Task},{KEY_Init, KEY_Task}
};// 系统初始化函数,调用所有组件的初始化函数
void System_Init(void) 
{unsigned char componentIndex;for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++) {components[componentIndex].init();}
}// 主循环,调用所有组件的任务函数
void main(void) 
{System_Init();  // 系统初始化while(1) {unsigned char componentIndex;for (componentIndex = 0; componentIndex < sizeof(components) / sizeof(components[0]); componentIndex++){components[componentIndex].task();  // 调用组件任务}}
}

以上几种,我都整理到单片机入门到高级资料+工具包了,大家可自行在朋友圈找我安排。

当然,以上都是最简易的代码模型,如果想用于实际项目,很多细节还要优化。

后面为了适应更复杂的项目,我基于以上这几种编程思维,重构了代码,使OS变得移植性和扩展性更强,用起来也更灵活。

我在2019年,也系统录制过关于这套架构的教程,粉丝可找我安排。

目前我们无际单片机特训营项目3和6就是采用这种架构,稳的一批。

如果想系统提升编程思维和代码水平,还是得从0到1去学习我们项目,并不是说技术有多难,而是很多思维和实现细节,没有参考,没人指点,靠自己需要摸索很久。

除了以上架构,更复杂的就是RTOS了。

不过一般对于有架构设计能力的工程师来说,更习惯于使用传统的裸机编程方式,这种方式可能更直观且可控。

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

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

相关文章

IDEA主题美化【保姆级】

前言 一款好的 IDEA 主题虽然不能提高我们的开发效率&#xff0c;但一个舒适简单的主题可以使开发人员更舒适的开发&#xff0c;时常换一换主题可以带来不一样的体验&#xff0c;程序员的快乐就这么简单。话不多说&#xff0c;先上我自己认为好看的主题设置。 最终效果图: 原…

qt学习篇---C++基础学习

本学习笔记学习下面视频总结&#xff0c;感兴趣可以去学习。讲的很详细 【北京迅为】嵌入式学习之QT学习篇_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1tp4y1i7EJ/?spm_id_from333.337.search-card.all.click&vd_source8827cc0da16223b9f2ad8ae7111de9e2 目录 C…

使用逆滤波算法deconvwnr恢复图像回复图像时,产生了很多横竖条纹。解决办法

使用逆滤波算法deconvwnr恢复图像回复图像时&#xff0c;产生了很多横竖条纹。解决办法 原来的代码 % 清除工作空间并关闭所有图形窗口 clear; clc; close all;% 读取原始图像 original_image imread(pic3.jpg);% 显示原始图像 subplot(131); imshow(original_image); title…

区块链技术:NFG元宇宙电商模式

大家好&#xff0c;我是微三云周丽 随着互联网技术的迅猛发展&#xff0c;电子商务行业逐渐崛起为现代经济的重要支柱。而在这一浪潮中&#xff0c;元宇宙电商以其独特的商业模式和巨大的发展潜力&#xff0c;成为行业的新宠。其中&#xff0c;NFG作为元宇宙电商模式的代表&am…

【无监督+自然语言】 GPT,BERT, GPT-2,GPT-3 生成式预训练模型方法概述 (Generative Pre-Traning)

主要参考 【GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【李沐论文精读】-2022.03.04】 https://www.bilibili.com/video/BV1AF411b7xQ/ 大语言模型综述&#xff1a; https://blog.csdn.net/imwaters/article/details/137019747 GPT与chatgpt的关系 图源&#xff1a;L…

YOLOv8-pose针对视频实时提取打印对应关节点序号及坐标

因为我在找如何提取YOLOv8-pose的关键点的时候&#xff0c;大多都是针对静态图像&#xff0c;视频直接套用不太行&#xff0c;因此就改进了一下&#xff0c;如下&#xff1a; 初步代码&#xff1a; import torch # 导入PyTorch库 import cv2 as cv # 导入OpenCV库并重命名为…

Leetcode-面试题 02.02. 返回倒数第 k 个节点

目录 题目 图解 代码 面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/description/ 题目 实现一种算法&#xff0c;找出单向链表中倒数第 k 个节点。返回该节点的值。 注意&…

《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

《深入理解mybatis原理》 MyBatis的架构设计以及实例分析 MyBatis是目前非常流行的ORM框架&#xff0c;它的功能很强大&#xff0c;然而其实现却比较简单、优雅。本文主要讲述MyBatis的架构设计思路&#xff0c;并且讨论MyBatis的几个核心部件&#xff0c;然后结合一个select查…

Skill Check: Fundamentals of Large Language Models

Skill Check: Fundamentals of Large Language Models 完结&#xff01;

如何快速获取城市地铁站点经纬度数据——以东莞地铁2号线为例

如何快速获取城市地铁站点经纬度数据——以东莞地铁2号线为例 在现代城市规划与交通研究中&#xff0c;地铁站点经纬度数据的获取显得尤为重要。这些数据不仅可以帮助我们了解城市的交通布局&#xff0c;还可以为城市规划、物流优化以及位置服务等多个领域提供有力的数据支持。…

鸿蒙launcher浅析

鸿蒙launcher浅析 鸿蒙launcher源码下载鸿蒙launcher模块launcher和普通的应用ui展示的区别 鸿蒙launcher源码下载 下载地址如下&#xff1a; https://gitee.com/openharmony/applications_launcher 鸿蒙launcher模块 下载页面已经有相关文件结构的介绍了 使用鸿蒙编辑器D…

IntelliJ IDEA - Lombok supports: OpenJDK javac, ECJ

问题描述 java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy26Lombok supports: OpenJDK javac, ECJ 解决方案 在 IDEA 设置中 File -> Settings 中找到配置如下&#xff1…

MO干货 | Matrixone-Operator 设计与实现

作者&#xff1a;吴叶磊 MO研发工程师 目录 Part 1.MatrixOne-Operator 设计 Part 2.集群 API 设计 Part 3.控制器实现 Part 4.应用状态管理 Part 5.总结 Part 1 MatrixOne-Operator 设计 尽管 K8S 原生提供了 StatefulSet API 来服务有状态应用的编排&#xff0c;但由于…

没有文件服务器,头像存哪里合适

没有文件服务器&#xff0c;头像存哪里合适 视频在bilibili&#xff1a;没有文件服务器&#xff0c;头像存哪里合适 1. 背景 之前有同学私信我说&#xff0c;他的项目只是想存个头像&#xff0c;没有别的文件存储需求&#xff0c;不想去用什么Fastdfs之类的方案搭建文件服务…

安卓常用组件(启停活动页面、活动之间传递信息、收发应用广播、操作后台服务)

启停活动页面 Activity的启动和结束 页面跳转可以使用startActivity接口&#xff0c;具体格式为startActivity(new Intent(this, 目标页面.class));。 关闭一个页面可以直接调用finish();方法即可退出页面。 Activity的生命周期 页面在安卓有个新的名字叫活动&#xff0c;因…

Linux系统编程---线程池并发服务器

模型原理分析&#xff1a; 线程池的关键优势在于它减少了每次任务执行时创建和销毁线程的开销 线程池的组成主要分为 3 个部分&#xff0c;这三部分配合工作就可以得到一个完整的线程池&#xff1a; 1. 任务队列&#xff0c;存储需要处理的任务&#xff0c;由工作的线程来处理…

关于google search console工具提交sitemap.xml无法抓取的问题解决办法

其实这个问题很好解决。 第一种情况&#xff1a;利用工具为我们的网站自动生成静态的sitemap.xml文件。这种可以检查下是否完整&#xff0c;然后上传到根目录下去&#xff0c;再去google search console提交我们的网站地图。 第二种情况&#xff1a;同样利用工具自动生成动态s…

时间序列模型(含python程序实现)

常用按时间顺序排列的一组随机变量来表示一个随机事件的时间序列&#xff0c;简记为 用表示该随机序列的n个有序观察值&#xff0c;称之为序列长度为n的观察值序列。 常用的时间序列模型 时间序列的预处理 拿到一个观察值序列后&#xff0c;首先要对它的纯随机性和平稳性进行…

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 目录 Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 一、简单介绍 二、问题现象 三、问题分析 四、使用空后处理&#xff0c;解决闪屏花屏的显示问题 五、空后处理完整代码 一、简单介绍 Unity 在…

秋招后端开发面试题 - Java语言基础(下)

目录 Java基础下前言面试题toString() 、String.valueof()、(String)&#xff1f;hashCode() 方法&#xff1f;hashCode 和 equals 方法判断两个对象是否相等&#xff1f;为什么重写 equals 时必须重写 hashCode 方法&#xff1f;String、StringBuffer、StringBuilder?String …