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

C++ 基于多设计模式下的同步异步⽇志系统-1准备工作

一.项目介绍

项⽬介绍
本项⽬主要实现⼀个⽇志系统, 其主要⽀持以下功能:
• ⽀持多级别⽇志消息
• ⽀持同步⽇志和异步⽇志
• ⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中
• ⽀持多线程程序并发写⽇志
• ⽀持扩展不同的⽇志落地⽬标地

二.日志系统的三种实现方式

实现方式原理简述优点缺点适用场景
1. 控制台输出 (printf/std::cout)直接在控制台输出日志信息,不进行落地文件记录简单、直观、便于开发调试无法记录历史日志、对线上调试不适用本地开发调试、单线程程序
2. 同步写日志在当前业务线程中执行日志格式化 + 写入文件操作,每条日志调用都同步 write()实现简单、数据可靠每条日志都阻塞主流程,尤其在高并发下 write IO 成为性能瓶颈简单后端系统、低并发写日志场景
3. 异步写日志主线程仅负责将日志写入缓冲区,由专门线程写日志到文件高性能、非阻塞、不影响业务流程,适合高并发实现复杂、涉及线程、锁、双缓冲,落地时间略有延迟高性能服务、后台系统、分布式

三.相关技术知识补充

1 不定参宏函数

#include <iostream>
#include <cstdarg>
#define LOG(fmt, ...) printf("[%s:%d] " fmt "\n", __FILE__, __LINE__,##__VA_ARGS__)
int main()
{LOG("%s-%s", "hello", "wws);return 0;
}

之前rpc项目介绍过。

解释 ##__VA_ARGS__

__VA_ARGS__ 是 C 语言宏的可变参数,它允许宏接受不定数量的参数。
## 用于处理 "参数为空" 的情况,它的作用是:
如果 __VA_ARGS__ 为空,就去掉前面的 ' , ',防止格式错误。
如果 __VA_ARGS__ 有内容,它会正常展开。

2.C⻛格不定参函数

#include <iostream>
#include <cstdarg>
void printNum(int n, ...)
{va_list al;va_start(al, n); // 让al指向n参数之后的第⼀个可变参数for (int i = 0; i < n; i++){int num = va_arg(al, int); // 从可变参数中取出⼀个整形参数std::cout << num << std::endl;}va_end(al); // 清空可变参数列表--其实是将al置空
}
int main()
{printNum(3, 11, 22, 33);printNum(5, 44, 55, 66, 77, 88);return 0;
}

printNum(int n, ...)的作用就是打印n个整型

1. va_list al;

定义一个变参处理变量 va_list 它是 C 语言提供的一个宏(实际上是一个结构体指针类型),专门用来处理 ... 这些变长参数。你可以把它理解为:一个“变参读取器”指针。

2.va_start(al, n);

初始化变参指针(定位起点)它告诉 al“变长参数”是从 n之后开始的,且后面参数的个数为n。(C 语言没有反射或参数数量的机制,编译器也不会告诉你 ... 有几个参数。必须通过最后一个确定参数的地址来推断后面变参的起始地址,这就是 va_start 的原理)

3.va_arg(al, int);

使用 va_arg() 逐个读取参数(大小为第二个类型的大小)。从 al 指向的地方读取一个 int 类型的值,并且把 al 自动向后移动。

4. va_end(ap);

清理资源(让 ap 无效)清空指针

#include <iostream>
#include <cstdarg>
void myprintf(const char *fmt, ...)
{// int vasprintf(char **strp, const char *fmt, va_list ap);char *res;va_list al;va_start(al, fmt);int len = vasprintf(&res, fmt, al);va_end(al);std::cout << res << std::endl;free(res);
}
int main()
{myprintf("%s-%d", "⼩明", 18);return 0;
}

你写了一个叫 myprintf 的函数,能像 printf 一样,接收格式字符串和多个参数,把结果 格式化成字符串,并通过 std::cout 打印出来。

fmt 是格式字符串:"%s-%d"

va_start(al, fmt); 告诉 al:从参数 fmt 后面的地方开始读取变参("小明", 18)。

vasprintf(&res, fmt, al);

这个函数做了三件事:

1.根据 fmt 和 al,拼出格式化后的字符串

2.自动调用 malloc 分配内存,存放结果字符串;

3.把 res 设为这个字符串的地址。

free(res);

因为 vasprintf 分配了堆内存,你必须用 free 手动释放,否则会内存泄漏。

3.C++⻛格不定参函数


#include <iostream>
void xprintf()
{std::cout << std::endl;
}
template <typename T, typename... Args>
void xprintf(const T &value, Args &&...args)
{std::cout << value << " ";if ((sizeof...(args)) > 0){xprintf(std::forward<Args>(args)...);}else{xprintf();}
}
int main()
{xprintf("wws");xprintf("wws", 666);xprintf("wws", "0721", 666);return 0;
}

参数说明:

  • T:当前要处理的第一个参数

  • Args...:剩下的变长参数包

行为流程:

  1. 打印当前的 value

  2. 如果还有参数(sizeof...(args) > 0)就递归调用 xprintf(...)

  3. 否则,调用 xprintf()(终点),输出一个换行

  • ... 在前面:定义一个 参数包

  • ... 在后面:展开一个 参数包

(std::forward<Args>(args)...) 完美转发剩余的参数,右值传递完还是右值,左值还是左值。

为什么要写xprintf()参数为空的特化函数?

模板会一直展开直到参数为空

模板的递归展开并不会因为你进入 else 分支而立即停止递归。递归停止是通过“没有更多参数”来控制的。关键点是 你在调用 xprintf() 时,会不断把剩余的参数传递给下一个递归调用,直到参数包为空。

所以执行else后,并不会结束,还会继续递归直到参数包为空,所以必须写参数包为空的特化函数。

四.设计模式

1.六大设计原则

1.单一职责原则(SRP)

定义:一个类只负责一项职责。

应用:

  • Logger 只负责组织和发起日志输出。

  • Formatter 专注于格式化日志内容。

  • Sink 专注于日志“落地”(文件/控制台等输出方式)。

  • LogMsg 专注于日志数据结构封装。


🔓 2. 开闭原则(OCP)

定义:对扩展开放,对修改关闭。

应用:

  • 增加新的日志输出格式、日志落地方式(如新增 TCP 日志输出)→ 新增类即可,无需改动原逻辑。

  • 格式化模块通过解析 %d %m %t 等 pattern 字符串,支持灵活扩展。


🔁 3. 里氏替换原则(LSP)

定义:子类对象可以替代父类对象使用。

应用:

  • 所有日志输出类继承自抽象类 LogSink,只要实现 log() 方法,就能无缝替换。

  • SyncLogger / AsyncLogger 都继承自 Logger,任何需要 Logger 的地方都可以使用这两个实现。


🔌 4. 依赖倒置原则(DIP)

定义:高层模块不应该依赖底层模块,二者都应该依赖抽象。

应用:

  • 所有 Sink 都通过 LogSink::ptr 操作,具体使用的是哪个子类并不关心。

  • 日志器的创建通过 Builder 构建,调用方不直接依赖 Logger 实现类。


🧼 5. 接口隔离原则(ISP)

定义:类不应依赖它不使用的方法。

应用:

  • Formatter::format() 只依赖 LogMsg 数据,不暴露额外无关的操作。

  • Logger 类的 debug/info/warn/... 分开封装,调用者按需使用。


🧍 6. 迪米特法则(LoD)

定义:只与直接朋友通信,降低耦合。

应用:

  • 日志器通过 Logger::Builder 封装所有配置细节,调用者无需了解 Sink/Formatter 等底层实现。

  • 管理器 loggerManager 提供统一接口 getLogger(),外部无需知道 Logger 的创建细节。


总结一句话:

“用抽象构建框架,用实现扩展细节”,整个日志系统正是依据这一原则,通过设计模式把每个模块解耦,提升了系统的灵活性与可扩展性。

2.单例模式

单例模式是一种常见的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。单例模式有两种实现方式 饿汉模式和懒汉模式

饿汉模式

程序启动时就会创建⼀个唯⼀的实例对象。 因为单例对象已经确定, 所以⽐较适⽤于多
线程环境中, 多线程获取单例对象不需要加锁, 可以有效的避免资源竞争, 提⾼性能。

//1.饿汉模式
class Singleton
{
private:static Singleton _eton;//在类内进行声明Singleton()// 私有构造函数:_data(66){std::cout<<"单例对象构造"<<std::endl;}~Singleton() {} // 私有析构函数Singleton (const Singleton&)=delete;//禁止拷贝Singleton&operator=(const Singleton&)=delete;//禁止赋值
private:int _data;
public:static Singleton& getInstance(){return _eton;}
};
Singleton Singleton:: _eton;//类外定义

1.构造析构私有 拷贝赋值函数禁止delete且私有

2.类内声明 静态成员变量 类外定义(程序运行时自动实例化)

3.类中提供静态函数(不需要类对象就能调用),用来获取单例对象。

优点

  • 线程安全:由于单例对象在程序启动时就已经创建,多个线程在调用 getInstance() 时无需加锁,可以避免资源竞争,因此性能较高。

  • 简单:代码结构简单,容易理解和实现。

缺点

  • 提前创建:单例对象会在程序启动时就创建,即使在程序运行过程中并不需要这个实例,也会被创建,这可能导致不必要的资源浪费。

  • 不可延迟加载:如果创建单例对象的过程非常复杂或资源消耗很大,程序启动时就会受到影响。

适用场景

  • 适合在程序启动时就需要加载的资源,例如配置管理、日志系统等。

  • 适用于实例的创建比较轻量,或者实例的创建和销毁不会占用太多资源的场景。

懒汉模式

第⼀次使⽤要使⽤单例对象的时候创建实例对象。如果单例对象构造特别耗时或者耗费济
源(加载插件、加载⽹络资源等), 可以选择懒汉模式, 在第⼀次使⽤的时候才创建对象。

//2.懒汉模式
class Singleton
{
private:Singleton()// 私有构造函数:_data(66){std::cout<<"单例对象构造"<<std::endl;}~Singleton() {} // 私有析构函数Singleton (const Singleton&)=delete;//禁止拷贝Singleton&operator=(const Singleton&)=delete;//禁止赋值
private:int _data;
public:static Singleton& getInstance(){static Singleton _eton;//只有第一次调用时创建实例(C++11 此时线程安全不需要加锁)return _eton;}
};

1.构造析构私有 拷贝赋值函数禁止delete且私有

2.在获取单例对象时getInstance()内部创建单例对象(static对象只会初始化一次)

优点

  • 延迟创建:单例对象只有在真正需要时才会被创建,避免了不必要的资源浪费,适用于实例化过程耗时或消耗资源的情况。

  • 线程安全使用 C++11 的 static 关键字保证静态局部变量在多线程环境下的安全初始化。

缺点

  • 延迟加载开销:虽然避免了程序启动时的资源消耗,但在首次调用 getInstance() 时,会有一定的延迟开销。

  • 复杂度较高:相比饿汉模式,懒汉模式的实现稍微复杂一些,尤其是早期版本的 C++,静态局部变量的线程安全性没有保证,需要额外的锁机制。

适用场景

  • 适合实例化开销较大、资源消耗较多的单例对象,或者对象的创建是延迟的、条件不固定的情况。

特性饿汉模式懒汉模式
实例化时机程序启动时即创建实例第一次调用 getInstance() 时创建实例
线程安全默认线程安全静态局部变量保证线程安全(C++11后)
内存消耗启动时即创建,可能浪费资源只有在首次访问时才创建,节省内存资源
性能更高性能,无锁定和延迟初次调用有延迟,可能有少许性能开销
实现复杂度简单易实现稍复杂,涉及线程安全和延迟加载
适用场景启动时必须加载的对象,资源轻量对象创建耗时或资源消耗较大的情况

3.工厂模式

1.简单工厂模式

通过一个统一的工厂类,根据传入的参数判断创建哪种产品(对象)。

所有产品类的创建逻辑都集中在一个工厂类中。

客户端↓
SimpleFactory::create("苹果") or "香蕉"↓
返回具体产品(Apple / Banana)

只有一个工厂,根据传入类型的不同,来生产不同的对象。

class Fruit {
public:virtual void show() = 0;
};class Apple : public Fruit {
public:void show() override { std::cout << "我是苹果\n"; }
};class Banana : public Fruit {
public:void show() override { std::cout << "我是香蕉\n"; }
};class FruitFactory {
public:static std::shared_ptr<Fruit> createFruit(const std::string &type) {if (type == "apple") return std::make_shared<Apple>();if (type == "banana") return std::make_shared<Banana>();return nullptr;}
};

✅ 优点:

  • 简单易懂、实现成本低。

  • 客户端不需要知道具体产品类名,只需要告诉工厂“我要什么”。

❌ 缺点:

  • 违反开闭原则:添加新产品必须修改工厂代码。

  • 工厂类过于臃肿,职责过重,易造成维护困难。

✅ 适用场景:

  • 产品种类较少,变动不频繁的小项目或初期开发阶段。

方法二:模板函数

template<typename T, typename... Args>
static std::shared_ptr<T> create(Args&&... args)
{return std::make_shared<T>(std::forward<Args>(args)...);
}

符合开闭原则

2.工厂方法模式

每个产品类对应一个具体工厂类。

抽象出一个工厂接口,具体工厂负责创建对应的产品。

客户端只需使用对应的工厂,不再传入类型参数。

客户端↓
AppleFactory::create()        BananaFactory::create()↓                             ↓
返回 Apple                    返回 Banana

有多个工厂,一个子类就对应一个工厂。

class Fruit {
public:virtual void show() = 0;
};class Apple : public Fruit {
public:void show() override { std::cout << "我是苹果\n"; }
};class Banana : public Fruit {
public:void show() override { std::cout << "我是香蕉\n"; }
};class FruitFactory {
public:virtual std::shared_ptr<Fruit> createFruit() = 0;
};class AppleFactory : public FruitFactory {
public:std::shared_ptr<Fruit> createFruit() override {return std::make_shared<Apple>();}
};class BananaFactory : public FruitFactory {
public:std::shared_ptr<Fruit> createFruit() override {return std::make_shared<Banana>();}
};

✅ 优点:

  • 遵循开闭原则:新增产品只需新增产品类和工厂类,无需修改现有代码。

  • 更加符合“职责单一”的设计原则。

❌ 缺点:

  • 每新增一个产品都要新增一个工厂类,类数量增多。

  • 不适合产品种类太多的场景,维护成本较高。

✅ 适用场景:

  • 产品变化频繁,且对扩展性有要求的中大型项目。

3.抽象工厂模式

不再是创建“单一”产品,而是创建产品族(多个功能相关的产品对象)。

定义一组工厂接口,每个工厂可以创建多个类型的产品。

有多种物品,水果 动物... 里面还可以细分苹果 香蕉,狗 羊

每一种物品对应一个工厂,每个工厂中有具体对象生成函数

所有工厂都继承于一个抽象工厂。

抽象工厂(AbstractFactory)↓------------------------↓                      ↓
水果工厂(FruitFactory)   动物工厂(AnimalFactory)↓                      ↓
createApple()            createDog()
createBanana()           createSheep()
#include <iostream>
#include <memory>
#include <string>// ==== 抽象产品 ====
class Fruit {
public:virtual void show() = 0;virtual ~Fruit() = default;
};class Animal {
public:virtual void voice() = 0;virtual ~Animal() = default;
};// ==== 具体产品 ====
class Apple : public Fruit {
public:void show() override {std::cout << "我是苹果🍎" << std::endl;}
};class Banana : public Fruit {
public:void show() override {std::cout << "我是香蕉🍌" << std::endl;}
};class Dog : public Animal {
public:void voice() override {std::cout << "汪汪汪🐶" << std::endl;}
};class Sheep : public Animal {
public:void voice() override {std::cout << "咩咩咩🐑" << std::endl;}
};// ==== 抽象工厂接口 ====
class AbstractFactory {
public:virtual ~AbstractFactory() = default;
};// ==== 水果工厂接口 ====
class FruitFactory : public AbstractFactory {
public:virtual std::shared_ptr<Fruit> createApple() = 0;virtual std::shared_ptr<Fruit> createBanana() = 0;
};// ==== 动物工厂接口 ====
class AnimalFactory : public AbstractFactory {
public:virtual std::shared_ptr<Animal> createDog() = 0;virtual std::shared_ptr<Animal> createSheep() = 0;
};// ==== 水果工厂实现 ====
class ConcreteFruitFactory : public FruitFactory {
public:std::shared_ptr<Fruit> createApple() override {return std::make_shared<Apple>();}std::shared_ptr<Fruit> createBanana() override {return std::make_shared<Banana>();}
};// ==== 动物工厂实现 ====
class ConcreteAnimalFactory : public AnimalFactory {
public:std::shared_ptr<Animal> createDog() override {return std::make_shared<Dog>();}std::shared_ptr<Animal> createSheep() override {return std::make_shared<Sheep>();}
};// ==== 工厂选择器 ====
class FactorySelector {
public:enum class Type { FRUIT, ANIMAL };static std::shared_ptr<AbstractFactory> getFactory(Type type) {if (type == Type::FRUIT) {return std::make_shared<ConcreteFruitFactory>();} else {return std::make_shared<ConcreteAnimalFactory>();}}
};// ==== 使用示例 ====
int main() {// 选择水果工厂auto fruitFactory = std::dynamic_pointer_cast<FruitFactory>(FactorySelector::getFactory(FactorySelector::Type::FRUIT));auto apple = fruitFactory->createApple();apple->show();auto banana = fruitFactory->createBanana();banana->show();// 选择动物工厂auto animalFactory = std::dynamic_pointer_cast<AnimalFactory>(FactorySelector::getFactory(FactorySelector::Type::ANIMAL));auto dog = animalFactory->createDog();dog->voice();auto sheep = animalFactory->createSheep();sheep->voice();return 0;
}

✅ 优点:

  • 遵循开闭原则,支持产品族的统一创建

  • 便于对产品进行分组管理,提高模块间协作性。

❌ 缺点:

  • 系统复杂度提高,类之间的依赖关系增多。

  • 如果要添加新产品(而不是产品族),修改成本大(会破坏工厂接口)。

✅ 适用场景:

  • 一个系统需要成组创建多个互相依赖的对象

  • 比如 GUI 库中,不同操作系统(Windows/Mac/Linux)下的按钮、菜单、文本框需要成套配合。

4.建造者模式

建造者模式是⼀种创建型设计模式, 使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象,能够将⼀个复杂的对象的构建与它的表⽰分离,提供⼀种创建对象的最佳⽅式。主要⽤于解决对象的构建过于复杂的问题。
建造者模式主要基于四个核⼼类实现:
• 抽象产品类:定义复杂对象结构、属性和接口
• 具体产品类:⼀个具体的产品对象类
• 抽象Builder类:创建⼀个产品对象所需的各个部件的抽象接⼝
• 具体产品的Builder类:实现抽象接⼝,构建各个部件
• 指挥者Director类:统⼀组建过程,提供给调⽤者使⽤,通过指挥者按顺序来构造产品

抽象产品类:需要设置的属性

具体产品类:不同产品设置的属性不同

抽象Builder类:设置对应的属性的接口

具体产品的Builder类:具体怎么设置产品属性 (实现接口)

指挥者Director类:设置属性的先后顺序

// 1. 抽象产品类
class Computer {std::string _board, _display, _os;void setBoard(...); void setDisplay(...); virtual void setOs() = 0;
};// 2. 具体产品类
class MacBook : public Computer {void setOs() override { _os = "Mac OS X"; }
};// 3. 抽象建造者
class Builder {virtual void buildBoard(...) = 0;virtual void buildDisplay(...) = 0;virtual void buildOs() = 0;virtual Computer::ptr build() = 0;
};// 4. 具体建造者
class MacBookBuilder : public Builder {Computer::ptr _computer;void buildBoard(...) override { _computer->setBoard(...); }...
};// 5. 指挥者
class Director {Builder::ptr _builder;void construct(...) {_builder->buildBoard(...);_builder->buildDisplay(...);_builder->buildOs();}
};
int main()
{Builder* buidler = new MackBookBuilder();std::unique_ptr<Director> pd(new Director(buidler));pd->construct("英特尔主板", "VOC显⽰器");Computer::ptr computer = buidler->build();std::cout << computer->toString();return 0;
}
角色类名职责描述
抽象产品类Computer定义电脑的组成部分(主板、显示器、系统)以及接口
具体产品类MacBook继承 Computer,实现操作系统的设定
抽象建造者Builder定义构建各部分(主板、显示器、OS)和最终组装的接口
具体建造者MacBookBuilder实现构建过程,封装构建细节,返回构造结果
指挥者(Director)Director控制建造流程,调用建造者接口完成构造

5.代理模式


代理模式指代理控制对其他对象的访问, 也就是代理对象控制对原对象的引⽤。在某些情况下,⼀个对象不适合或者不能直接被引⽤访问,⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤。

代理模式的结构包括⼀个是真正的你要访问的对象(⽬标类)、⼀个是代理对象。⽬标对象与代理对象实现同⼀个接⼝,先访问代理类再通过代理类访问⽬标对象。代理模式分为静态代理、动态代理:
静态代理指的是,在编译时就已经确定好了代理类和被代理类的关系。也就是说,在编译时就已经确定了代理类要代理的是哪个被代理类。
• 动态代理指的是,在运⾏时才动态⽣成代理类,并将其与被代理类绑定。这意味着,在运⾏时才能确定代理类要代理的是哪个被代理类。

实现了一个“租房场景”的静态代理模式

  • 房东(Landlord)被代理对象(目标对象)

  • 中介(Intermediary)代理对象

  • 通过中介代理类来控制、增强对房东租房功能的访问

#include <iostream>
#include <string>// 抽象租房接口
class RentHouse {
public:virtual void rentHouse() = 0;virtual ~RentHouse() = default;
};// 房东类:目标对象(实际提供租房服务)
class Landlord : public RentHouse {
public:void rentHouse() override {std::cout << "房东:将房子租出去\n";}
};// 中介代理类:代理对象,封装对房东的访问并增强功能
class Intermediary : public RentHouse {
public:void rentHouse() override {std::cout << "中介:发布招租启示\n";std::cout << "中介:带人看房\n";_landlord.rentHouse();  // 委托给房东完成真正的租房std::cout << "中介:租后负责维修服务\n";}private:Landlord _landlord;  // 中介内部持有真实房东对象
};// 客户端调用
int main() {Intermediary intermediary;intermediary.rentHouse();  // 客户通过代理租房return 0;
}
→ 中介的 rentHouse()→ 发布招租启事→ 带人看房→ 调用房东的 rentHouse()(真正租出)→ 负责租后维修

房东只做了“租出去”这一件事,其他琐事都由中介代理处理,体现了代理模式“控制访问 + 功能增强”的特性。

相关文章:

C++ 基于多设计模式下的同步异步⽇志系统-1准备工作

一.项目介绍 项⽬介绍 本项⽬主要实现⼀个⽇志系统&#xff0c; 其主要⽀持以下功能: • ⽀持多级别⽇志消息 • ⽀持同步⽇志和异步⽇志 • ⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中 • ⽀持多线程程序并发写⽇志 • ⽀持扩展不同的⽇志落地⽬标地 二.日志系统的三种实现…...

c# MES生产进度看板,报警看板 热流道行业可用实时看生产进度

MES生产进度看板&#xff0c;报警看板 热流道行业可用实时看生产进度 背景 本软件是给宁波热流道行业客户开发的生产电子看板软件系统 功能 1.录入工艺流程图&#xff08;途程图&#xff09;由多个站别组成。可以手动设置每个工艺站点完成百分比。 2.可以看生成到哪个工…...

C语言学习之预处理指令

目录 预定义符号 #define的应用 #define定义常量 #define定义宏 带有副作用的宏参数 宏替换的规则 函数和宏定义的区别 #和## #运算符 ##运算符 命名约定 #undef ​编辑 命令行定义 条件编译 头文件包含 头文件被包含的方式 1.本地头文件包含 2.库文件包含 …...

腾讯wxg企业微信 后端开发一面

UDP安全吗&#xff0c;怎么修改让其安全&#xff1f; packet header QUIC FrameHeader TCP的三个窗口 滑动 发送 拥塞&#xff0c; 怎么用UDP使用类似的功能 怎么确认消息是否收到? TCP的拥塞控制是怎么样的 HTTPS的握手流程 MySQL为什么用B树 红黑树等结构也能在叶子节点实现…...

【Hot100】 73. 矩阵置零

目录 引言矩阵置零我的解题优化优化思路分步解决思路为什么必须按照这个顺序处理&#xff1f;完整示例演示总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;【Hot100】 73. 矩阵置零❣️ 寄语&#xff…...

c++_csp-j算法 (2)

目录 BFS搜索(广度优先搜索) 讲解 BFS搜索算法原理 BFS搜索算法实现 BFS搜索算法的应用 例题(1) P1032 [NOIP 2002 提高组] 字串变换 例题(2) P1443 马的遍历 BFS搜索(广度优先搜索) 讲解 BFS搜索算法原理 广度优先搜索(BFS)算法是一种图的搜索算法,用于遍历…...

学习笔记: Mach-O 文件

“结构决定性质,性质决定用途”。如果不了解结构,是很难真正理解的。 通过一个示例的可执行文件了解Mach-O文件的结构 Mach-O基本结构 Header: &#xff1a;文件类型、目标架构类型等Load Commands&#xff1a;描述文件在虚拟内存中的逻辑结构、布局Data: 在Load commands中…...

基于GRPO将QWEN训练为和deepseek一样的推理模型!

GRPO 群体相对策略优化&#xff08;GRPO&#xff09;算法最初由deepseek团队提出&#xff0c;是近端策略优化(PPO)的一个变体。 GRPO 是一种在线学习算法&#xff0c;它通过使用训练过程中已训练模型自身生成的数据进行迭代改进。GRPO 目标背后的逻辑是在确保模型与参考策略保…...

STM32 外部中断EXTI

目录 外部中断基础知识 STM32外部中断框架 STM32外部中断机制框架 复用功能 重映射 中断嵌套控制器NVIC 外部中断按键控制LED灯 外部中断基础知识 STM32外部中断框架 中断的概念&#xff1a;在主程序运行过程中&#xff0c;出现了特点的中断触发条件&#xff0c;使得…...

Codex CLI - 自然语言命令行界面

本文翻译整理自&#xff1a;https://github.com/microsoft/Codex-CLI 文章目录 一、关于 Codex CLI相关链接资源 二、安装系统要求安装步骤 三、基本使用1、基础操作2、多轮模式 四、命令参考五、提示工程与上下文文件自定义上下文 六、故障排查七、FAQ如何查询可用OpenAI引擎&…...

健身会员管理系统(ssh+jsp+mysql8.x)含运行文档

健身会员管理系统(sshjspmysql8.x) 对健身房的健身器材、会员、教练、办卡、会员健身情况进行管理&#xff0c;可根据会员号或器材进行搜索&#xff0c;查看会员健身情况或器材使用情况。...

数据结构——快排和归并排序(非递归)

快速排序和归并排序一般都是用递归来实现的&#xff0c;但是掌握非递归也是很重要的&#xff0c;说不定在面试的时候面试官突然问你快排或者归并非递归实现&#xff0c;递归有时候并不好&#xff0c;在数据量非常大的时候效率就不好&#xff0c;但是使用非递归结果就不一样了&a…...

Trae,字节跳动推出的 AI 编程助手插件

Trae 插件是 Trae 旗下全新一代的人工智能编程助手&#xff08;前身为 MarsCode 编程助手&#xff09;&#xff0c;以插件形式集成在本地开发环境中&#xff0c;具备极高的兼容性和灵活性&#xff0c;旨在提升开发效率和代码质量。它支持超过100种编程语言&#xff0c;兼容主流…...

Qt项目——Tcp网络调试助手服务端与客户端

目录 前言结果预览工程文件源代码一、开发流程二、Tcp协议三、Socket四、Tcp服务器的关键流程五、Tcp客户端的关键流程六、Tcp服务端核心代码七、客户端核心代码总结 前言 这期要运用到计算机网络的知识&#xff0c;要搞清楚Tcp协议&#xff0c;学习QTcpServer &#xff0c;学…...

2021-11-10 C++蜗牛爬井进3退1求天数

缘由C大一编程题目。-编程语言-CSDN问答 int n 0, t 0;cin >> n;while ((n - 3)>0)n, t;cout << t << endl;...

玛哈特整平机:工业制造中的关键设备

在现代工业制造中&#xff0c;平整度是衡量材料加工质量的核心指标之一。无论是金属板材、塑料片材还是复合材料&#xff0c;若存在弯曲、翘曲或波浪形缺陷&#xff0c;将直接影响后续加工效率和成品质量。整平机&#xff08;又称校平机、矫平机&#xff09;作为解决这一问题的…...

LINUX419 更换仓库(没换成)find命令

NAT模式下虚拟机需与网卡处在同一个网段中吗 和VM1同个网段 会不会影响 这个很重要 是2 改成点2 倒是Ping通了 为啥ping百度 ping到别的地方 4399 倒是ping通了 准备下载httpd包 下不下来 正在替换为新版本仓库 报错 failure: repodata/repomd.xml from local: [Er…...

C# 预定义类型全解析

在 C# 编程中&#xff0c;预定义类型是基础且重要的概念。下面我们来详细了解 C# 的预定义类型。 预定义类型概述 C# 提供了 16 种预定义类型&#xff0c;包含 13 种简单类型和 3 种非简单类型。所有预定义类型的名称都由全小写字母组成。 预定义简单类型 预定义简单类型表…...

【仓颉 + 鸿蒙 + AI Agent】CangjieMagic框架(16):ReactExecutor

CangjieMagic框架&#xff1a;使用华为仓颉编程语言编写&#xff0c;专门用于开发AI Agent&#xff0c;支持鸿蒙、Windows、macOS、Linux等系统。 这篇文章剖析一下 CangjieMagic 框架中的 ReactExecutor。 这个执行器名字中的"React"代表"Reasoning and Acti…...

13.第二阶段x64游戏实战-分析人物等级和升级经验

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;12.第二阶段x64游戏实战-远程调试 效果图&#xff1a; 如下图红框&#xff0c;…...

Linux疑难杂惑 | 云服务器重装系统后vscode无法远程连接的问题

报错原因&#xff1a;本地的known_hosts文件记录服务器信息与现服务器的信息冲突了&#xff0c;导致连接失败。 解决方法&#xff1a;找到本地的known_hosts文件&#xff0c;把里面的所有东西删除后保存就好了。 该文件的路径可以在报错中寻找&#xff1a;比如我的路径就是&a…...

使用EXCEL绘制平滑曲线

播主播主&#xff0c;你都多少天没更新了&#xff01;&#xff01;&#xff01;泥在干什么&#xff1f;你还做这个账号麻&#xff1f;&#xff01;&#xff01;&#xff01; 做的做的&#xff08;哭唧唧&#xff09;&#xff0c;就是最近有些忙&#xff0c;以及…… 前言&…...

你的电脑在开“外卖平台”?——作业管理全解析

你的电脑在开“外卖平台”&#xff1f;——作业管理全解析 操作系统系列文章导航&#xff08;点击跳转&#xff09; 程序员必看&#xff1a;揭开操作系统的神秘面纱 &#xff1a;从进程、内存到设备管理&#xff0c;全面解析操作系统的核心机制与日常应用。告别电脑卡顿&#x…...

平均池化(Average Pooling)

1. 定义与作用​​ ​​平均池化​​是一种下采样操作&#xff0c;通过对输入区域的数值取​​平均值​​来压缩数据空间维度。其核心作用包括&#xff1a; ​​降低计算量​​&#xff1a;减少特征图尺寸&#xff0c;提升模型效率。​​保留整体特征​​&#xff1a;平滑局部…...

JavaScript中的Event事件对象详解

一、事件对象&#xff08;Event&#xff09;概述 1. 事件对象的定义 event 对象是浏览器自动生成的对象&#xff0c;当用户与页面进行交互时&#xff08;如点击、键盘输入、鼠标移动等&#xff09;&#xff0c;事件触发时就会自动传递给事件处理函数。event 对象包含了与事件…...

OSPF综合实验(HCIP)

1&#xff0c;R5为ISP&#xff0c;其上只能配置Ip地址&#xff1b;R4作为企业边界路由器&#xff0c; 出口公网地址需要通过ppp协议获取&#xff0c;并进行chap认证 2&#xff0c;整个OSPF环境IP基于172.16.0.0/16划分&#xff1b; 3&#xff0c;所有设备均可访问R5的环回&…...

Unreal 从入门到精通之如何接入MQTT

文章目录 前言MQTT 核心特性MQTT 在 UE5 中的应用场景在 UE5 中集成 MQTTMqtt Client 的APIMqtt Client 使用示例最后前言 MQTT(Message Queuing Telemetry Transport)是一种专为物联网(IoT)和低带宽、高延迟网络环境设计的轻量级消息传输协议。它采用发布/订阅(Pub/Sub)…...

数据结构实验6.2:稀疏矩阵的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;问题描述三&#xff0c;基本要求四、算法分析&#xff08;一&#xff09;稀疏矩阵三元组表示法存储结构&#xff08;二&#xff09;插入算法&#xff08;三&#xff09;创建算法&#xff08;四&#xff09;输出算法&#xff08;五…...

BDO分厂积极开展“五个一”安全活动

BDO分厂为规范化学习“五个一”活动主题&#xff0c;按照“上下联动、分头准备 、差异管理、资源共享”的原则&#xff0c;全面激活班组安全活动管理新模式&#xff0c;正在积极开展班组安全活动&#xff0c;以单元班组形式对每个班组每周组织一次“五个一”安全活动。 丁二醇单…...

那就聊一聊mysql的锁

MySQL 的锁机制是数据库并发控制的核心&#xff0c;作为 Java 架构师需要深入理解其实现原理和适用场景。以下是 MySQL 锁机制的详细解析&#xff1a; 一、锁的分类维度 1. 按锁粒度划分 锁粒度特点适用场景​全局锁​锁定整个数据库&#xff08;FLUSH TABLES WITH READ LOC…...

Python番外——常用的包功能讲解和分类组合

目录 1. Web开发框架与工具 2. 数据处理与分析 3. 网络请求与爬虫 4. 异步编程 5. 数据库操作 6. 图像与多媒体处理 7. 语言模型与NLP 8. 安全与加密 9. 配置与工具 10. 其他工具库 11.典型组合场景 此章节主要是记录我所使用的包&#xff0c;以及模块。方便供自己方…...

【mongodb】数据库操作

目录 1. 查看所有数据库2. 切换到指定数据库&#xff08;若数据库不存在&#xff0c;则创建&#xff09;3. 查看当前使用的数据库4. 删除当前数据库5.默认数据库 1. 查看所有数据库 1.show dbs2.show databases 2. 切换到指定数据库&#xff08;若数据库不存在&#xff0c;则…...

四月下旬系列

CUHKSZ 校赛 期中考试 DAY -1。 省流&#xff1a;前 1h 切 6 题&#xff0c;后 3h 过 1 题&#xff0c;读错一个本来很【】的题&#xff0c;被大模拟构造创【】了。 本地除了 VSCode 没有 Extensions&#xff0c;别的和省选差不多。使用 DEVC。 前 6 题难度 < 绿&#x…...

计算机网络 3-4 数据链路层(局域网)

4.1 局域网LAN 特点 1.覆盖较小的地理范围 2.较低的时延和误码率 3.局域网内的各节点之间 4.支持单播、广播、多播 分类 关注三要素 &#xff08;出题点&#xff09; ①拓扑结构 ②传输介质 ③介质访问控制方式 硬件架构 4.2 以太网 4.2.1 层次划分 4.2.2 物理层标准…...

WebSocket介绍

在网页聊天项目中&#xff0c;为了实现消息的发送和及时接收&#xff0c;我们使用了WebSocket&#xff0c;接下来就简单介绍一下这个WebSocket。 了解消息的转发逻辑 当两个不同客户端在不同的局域网中互相发送消息时&#xff0c;假如这两个客户端分别是a和b&#xff0c;因为…...

rpcrt4!COMMON_AddressManager函数分析之和全局变量rpcrt4!AddressList的关系

第一部分&#xff1a; 1: kd> x rpcrt4!addresslist 77c839dc RPCRT4!AddressList 0x00000000 1: kd> g Breakpoint 2 hit RPCRT4!OSF_ADDRESS::CompleteListen: 001b:77c0c973 55 push ebp 1: kd> g Breakpoint 11 hit RPCRT4!COMMON_Addr…...

Java Web 之 Tomcat 100问

Tomcat 是什么&#xff1f; Tomcat 是一个开源的 Java Servlet 容器和 Web 容器。 Tomcat 的主要功能有哪些&#xff1f; 三大主要功能&#xff1a; 运行 Java Web 应用。处理 HTTP 请求。管理 Web 应用。 如何安装 Tomcat &#xff1f; 下载 Tomcat 安装包&#xff08;A…...

ESB —— 企业集成架构的基石:功能、架构与应用全解析

企业服务总线&#xff08;Enterprise Service Bus&#xff0c;ESB&#xff09;是一种重要的企业级集成架构&#xff0c;以下为你详细介绍&#xff1a; 一、概念与定义 ESB 是一种基于面向服务架构&#xff08;SOA&#xff09;的中间件技术&#xff0c;它充当了企业内部不同应…...

wordpress SMTP配置qq邮箱发送邮件,新版QQ邮箱授权码获取方法

新版的QQ邮箱界面不同了&#xff0c;以下是新版的设置方法&#xff1a; 1. 进入邮箱后&#xff0c;点右上角的设置图标&#xff1a; 2. 左下角的菜单里&#xff0c;选择“账号与安全” &#xff1a; 3. 然后如下图&#xff0c;开启SMTP 服务&#xff1a; 4. 按提示验证短信&am…...

【操作系统原理04】进程同步

文章目录 大纲一.进程同步与进程互斥0.大纲1.同步2.互斥 二.进程互斥的软件实现方法0.大纲1.单标志法2.双标志先检查法3.双标志后检查法4.Peterson算法 三.进程互斥的硬件实现方法0.大纲1.中断屏蔽方法2.TestAndSet指令3.Swap指令 四.互斥锁五.信号量机制0.大纲1.概念2.整形信号…...

Java ThreadPoolExecutor 深度解析:从原理到实战

在 Java 的多线程编程领域&#xff0c;ThreadPoolExecutor是一个至关重要的工具类&#xff0c;它为开发者提供了强大且灵活的线程池管理能力。合理使用ThreadPoolExecutor&#xff0c;不仅能够提升应用程序的性能和响应速度&#xff0c;还能有效控制资源消耗&#xff0c;避免因…...

MCP 协议——AI 世界的“USB-C 接口”:解锁智能协作的新时代

在过去十年中&#xff0c;科技的进步已经改变了我们日常生活的方方面面。从智能手机的普及到物联网的快速发展&#xff0c;人们的生活被各种创新的技术重新定义。今天&#xff0c;我们即将迎来另一个里程碑式的转折点——MCP 协议的推出&#xff0c;它将为人工智能世界的协作与…...

知识就是力量——一些硬件的使用方式

硬件平台 正点原子ATK-MD0430 V2.0&#xff08;4.3寸TFT LCD电容触摸屏/使用cc2530控制&#xff09;1.硬件连接2. 软件驱动实现3. 优化与注意事项4. 示例工程参考5. 常见问题 正点原子ATK-MD0430 V2.0&#xff08;4.3寸TFT LCD电容触摸屏/使用cc2530控制&#xff09; 1.硬件连…...

机器学习(1)— 开发环境安装

机器学习&#xff08;1&#xff09;— 准备开发环境 一、前言 二、Ubuntu开发环境安装 1、NumPy安装 使用如下命令安装&#xff1a; sudo apt-get install python3-numpy2、PyTorch 安装 由于我电脑暂时没有英伟达显卡&#xff0c;暂时安装CPU版&#xff1a; pip3 insta…...

深入实战:使用C++开发高性能RESTful API

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…...

C++之虚函数 Virtual Function

1. 普通虚函数&#xff08;Virtual Function&#xff09; 定义&#xff1a;基类中用 virtual 声明&#xff0c;允许派生类 覆盖&#xff08;Override&#xff09;。特点&#xff1a; 基类可提供默认实现。派生类可选择性覆盖&#xff08;若不覆盖&#xff0c;则调用基类版本&a…...

【java实现+4种变体完整例子】排序算法中【选择排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是选择排序的详细解析&#xff0c;包含基础实现、常见变体的完整代码示例&#xff0c;以及各变体的对比表格&#xff1a; 一、选择排序基础实现 原理 每一轮遍历未排序部分&#xff0c;找到最小元素并交换到当前起始位置&#xff0c;逐步构建已排序序列。 代码示例 pu…...

DNS主从同步实验

dns域名解析原理 实验步骤1、主dns要完成dns解析&#xff1a;192.168.21.128 [rootlocalhost ~]# yum install bind -y [rootlocalhost ~]# systemctl start named [rootlocalhost ~]# vim /etc/named.conf options { listen-on port 53 { any; }; direct…...

UIjavaScritIU

1、直接执行js脚本&#xff1a;document.documentElement.scrollTop1000 document.getElementById(“su”).click() 弊端&#xff1a; js自己带的元素定位方法不如selenium的丰富 不支持xpath css 等 定位元素操作不是很灵活。 需要借助js脚本传入 -selenium定位 js 负责执行动…...

Manus技术架构、实现内幕及分布式智能体项目实战 线上高级实训班

Manus技术架构、实现内幕及分布式智能体项目实战 线上高级实训班 模块一&#xff1a;解密Manus分布式多智能体工作原理和架构内幕  基于Claude和Qwen的大模型智能体Manus为何能够迅速成为全球讨论热度最高、使用体验最好、产业界最火爆的大模型智能体产品&#xff1f;  Ma…...