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

C++项目实战——基于多设计模式下的同步异步日志系统-⑪-日志器管理类与全局建造者类设计(单例模式)

文章目录

  • 专栏导读
  • 日志器建造者类完善
  • 单例日志器管理类设计思想
  • 单例日志器管理类设计
  • 全局建造者类设计
  • 日志器类、建造者类整理
  • 日志器管理类测试

专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 C++项目——基于多设计模式下的同步与异步日志系统

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法Linux

在这里插入图片描述

日志器建造者类完善

实现了异步日志器设计之后,将异步日志器添加到日志器建造者类当中。

// 1.抽象一个日志器建造者类(完成日志器所需零部件的构建 & 日志器的构建)
//  1.设置日志器类型
//  2.将不同类型的日志器的创建放到同一个日志器建造者类中完成
enum class LoggerType
{LOGGER_SYNC,LOGGER_ASYNC
};
class LoggerBuilder
{
public:LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),_limit_level(LogLevel::value::DEBUG),_looper_type(AsyncType::ASYNC_SAFE){}void buildLoggerType(LoggerType type) { _logger_type = type; }void buildEnableUnSafeAsync() { _looper_type = AsyncType::ASYNC_UNSAFE; }void buildLoggerName(const std::string &name) { _logger_name = name; }void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }void buildFormatter(const std::string &pattern){_formatter = std::make_shared<Formatter>(pattern);}template <typename SinkType, typename... Args>void buildSink(Args &&...args) // 由用户自己决定落地方式{LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);_sinks.push_back(psink);}virtual Logger::ptr build() = 0;
protected:AsyncType _looper_type;LoggerType _logger_type;std::string _logger_name;std::atomic<LogLevel::value> _limit_level;Formatter::ptr _formatter;std::vector<LogSink::ptr> _sinks;
};
/*2.派生出具体的建造者类---局部日志器的建造者 & 全局日志器的建造者*/
class LocalLoggerBuilder : public LoggerBuilder
{
public:Logger::ptr build() override{assert(_logger_name.empty() == false);if (_formatter.get() == nullptr){_formatter = std::make_shared<Formatter>();}if (_sinks.empty()){buildSink<StdOutSink>();}if (_logger_type == LoggerType::LOGGER_ASYNC){return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);}return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);}
};

单例日志器管理类设计思想

通过局部日志器建造者创建的日志器受到作用域的限制。但是日志的输出,我们希望能够在任意位置。

因此为了突破日志器作用域的限制,我们创建一个日志器管理类,且该类是一个单例类,这样我们就可以在任意位置通过单例管理器单例获取到指定的日志器进行输出了。

基于单例日志器管理类的设计思想,我们对于日志器建造者类进行继承,继承出一个全局日志器建造者类,实现一个日志器在创建完毕后,直接将其添加到单例的日志器管理器当中,以便于能够在任意位置通过日志器名称能够获取到指定的日志器进行输出。

日志器管理器的作用

  • 对所有创建的日志器进行管理
  • 可以在程序的任意位置进,获取相同的单例对象,获取其中的日志器进行日志输出

单例日志器管理类设计

管理的成员:

  • 默认日志器
  • 所管理的日志器数组(使用哈希表,日志器名称为key,日志器对象为value);
  • 互斥锁

提供的操作:

  • 添加日志器管理
  • 判断是否管理了指定名称的日志器
  • 获取指定名称的日志器
  • 获取默认日志器
class LoggerManager
{
public:static LoggerManager& getInstance(){// c++11之后,静态局部变量,编译器在编译的层面实现了线程安全// 当静态局部变量在没有构造完成之前,其他线程进入就会阻塞static LoggerManager eton;return eton;}void addLogger(Logger::ptr &logger){if(hasLogger(logger->name())) return;std::unique_lock<std::mutex> lock(_mutex);_loggers.insert(std::make_pair(logger->name(), logger));}bool hasLogger(const std::string name){std::unique_lock<std::mutex> lock(_mutex);auto it = _loggers.find(name);if(it == _loggers.end()){return false;}return true;}Logger::ptr getLogger(const std::string name){std::unique_lock<std::mutex> lock(_mutex);auto it = _loggers.find(name);if(it == _loggers.end()){return Logger::ptr();}return it->second;}Logger::ptr rootLogger(){return _root_logger;}
private:// 构造函数私有化LoggerManager(){std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::LocalLoggerBuilder());builder->buildLoggerName("root");_root_logger = builder->build();_loggers.insert(std::make_pair("root", _root_logger));}
private:std::mutex _mutex;Logger::ptr _root_logger; // 默认日志器std::unordered_map<std::string, Logger::ptr> _loggers // 日志器数组;
};

全局建造者类设计

为了降低用户的使用复杂度,我们提供一个全局日志器建造者类。全局建造者类的设计思想非常简单,即在局部的基础上增加了一个功能:

  • 将日志器添加到单例对象中
class GlobalLoggerBuilder : public LoggerBuilder
{
public:Logger::ptr build() override{assert(_logger_name.empty() == false);if (_formatter.get() == nullptr){_formatter = std::make_shared<Formatter>();}if (_sinks.empty()){buildSink<StdOutSink>();}Logger::ptr logger;if (_logger_type == LoggerType::LOGGER_ASYNC){logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);}else{logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);}LoggerManager::getInstance().addLogger(logger);return logger;}
};

日志器类、建造者类整理

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <cstdarg>
#include <atomic>
#include <thread>
#include <mutex>
#include <unordered_map>namespace LOG
{class Logger{public:using ptr = std::shared_ptr<Logger>;Logger(const std::string &logger_name,LogLevel::value level,Formatter::ptr &formatter,std::vector<LogSink::ptr> &sinks) : _logger_name(logger_name),_limit_level(level),_formatter(formatter),_sinks(sinks.begin(), sinks.end()){}const std::string& name(){ return _logger_name; }void debug(const std::string &file, size_t line, const std::string &fmt, ...){// 通过传入的参数构造出一个日志消息对象, 进行日志格式化,最终落地// 判断当前的日志是否达到了输出等级if (LogLevel::value::DEBUG < _limit_level){return;}// 对fmt格式化字符串和不定参数进行字符串组织, 得到的日志消息字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == 1){std::cout << "vasprintf failed\n";return;}va_end(ap);serialize(LogLevel::value::DEBUG, file, line, res);free(res);}void info(const std::string &file, size_t line, const std::string &fmt, ...){// 通过传入的参数构造出一个日志消息对象, 进行日志格式化,最终落地if (LogLevel::value::INFO < _limit_level){return;}// 对fmt格式化字符串和不定参数进行字符串组织, 得到的日志消息字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == 1){std::cout << "vasprintf failed\n";return;}va_end(ap);serialize(LogLevel::value::INFO, file, line, res);free(res);}void warn(const std::string &file, size_t line, const std::string &fmt, ...){// 通过传入的参数构造出一个日志消息对象, 进行日志格式化,最终落地if (LogLevel::value::WARN < _limit_level){return;}// 对fmt格式化字符串和不定参数进行字符串组织, 得到的日志消息字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == 1){std::cout << "vasprintf failed\n";return;}va_end(ap);serialize(LogLevel::value::WARN, file, line, res);free(res);}void error(const std::string &file, size_t line, const std::string &fmt, ...){// 通过传入的参数构造出一个日志消息对象, 进行日志格式化,最终落地if (LogLevel::value::ERROR < _limit_level){return;}// 对fmt格式化字符串和不定参数进行字符串组织, 得到的日志消息字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == 1){std::cout << "vasprintf failed\n";return;}va_end(ap);serialize(LogLevel::value::ERROR, file, line, res);free(res);}void fatal(const std::string &file, size_t line, const std::string &fmt, ...){// 通过传入的参数构造出一个日志消息对象, 进行日志格式化,最终落地if (LogLevel::value::FATAL < _limit_level){return;}// 对fmt格式化字符串和不定参数进行字符串组织, 得到的日志消息字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == 1){std::cout << "vasprintf failed\n";return;}va_end(ap);serialize(LogLevel::value::FATAL, file, line, res);free(res);}protected:void serialize(LogLevel::value level, const std::string &file, size_t line, char *str){// 构造LogMsg对象LogMsg msg(level, line, file, _logger_name, str);// 通过格式化工具对LogMsg进行格式化, 得到格式化后的日志字符串std::stringstream ss;_formatter->format(ss, msg);// 对日志进行落地log(ss.str().c_str(), ss.str().size());}virtual void log(const char *data, size_t len) = 0;protected:std::mutex _mutex;std::string _logger_name;                  // 日志器名称std::atomic<LogLevel::value> _limit_level; // 限制输出等级Formatter::ptr _formatter;std::vector<LogSink::ptr> _sinks;};class SyncLogger : public Logger{public:SyncLogger(const std::string &logger_name,LogLevel::value level,LOG::Formatter::ptr &formatter,std::vector<LogSink::ptr> &sinks) : Logger(logger_name, level, formatter, sinks){}protected:void log(const char *data, size_t len){std::unique_lock<std::mutex> lock(_mutex);if (_sinks.empty())return;for (auto &sink : _sinks){sink->log(data, len);}}};class AsyncLogger : public Logger{public:AsyncLogger(const std::string &logger_name,LogLevel::value level,LOG::Formatter::ptr &formatter,std::vector<LogSink::ptr> &sinks,AsyncType looper_type): Logger(logger_name, level, formatter, sinks),_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type)){}// 将数据写入缓冲区 void log(const char *data, size_t len){_looper->push(data, len);}// 设计一个实际落地函数void realLog(Buffer &buf){if (_sinks.empty())return;for (auto &sink : _sinks){sink->log(buf.begin(), buf.readAbleSize());}}private:AsyncLooper::ptr _looper; // 异步工作器};// 1.抽象一个日志器建造者类(完成日志器所需零部件的构建 & 日志器的构建)//  1.设置日志器类型//  2.将不同类型的日志器的创建放到同一个日志器建造者类中完成enum class LoggerType{LOGGER_SYNC,LOGGER_ASYNC};class LoggerBuilder{public:LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),_limit_level(LogLevel::value::DEBUG),_looper_type(AsyncType::ASYNC_SAFE){}void buildLoggerType(LoggerType type) { _logger_type = type; }void buildEnableUnSafeAsync() { _looper_type = AsyncType::ASYNC_UNSAFE; }void buildLoggerName(const std::string &name) { _logger_name = name; }void buildLoggerLevel(LogLevel::value level) { _limit_level = level; }void buildFormatter(const std::string &pattern){_formatter = std::make_shared<Formatter>(pattern);}template <typename SinkType, typename... Args>void buildSink(Args &&...args) // 由用户自己决定落地方式{LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);_sinks.push_back(psink);}virtual Logger::ptr build() = 0;protected:AsyncType _looper_type;LoggerType _logger_type;std::string _logger_name;std::atomic<LogLevel::value> _limit_level;Formatter::ptr _formatter;std::vector<LogSink::ptr> _sinks;};/*2.派生出具体的建造者类---局部日志器的建造者 & 全局日志器的建造者*/class LocalLoggerBuilder : public LoggerBuilder{public:Logger::ptr build() override{assert(_logger_name.empty() == false);if (_formatter.get() == nullptr){_formatter = std::make_shared<Formatter>();}if (_sinks.empty()){buildSink<StdOutSink>();}if (_logger_type == LoggerType::LOGGER_ASYNC){return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);}return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);}};class LoggerManager{public:static LoggerManager& getInstance(){// c++11之后,静态局部变量,编译器在编译的层面实现了线程安全// 当静态局部变量在没有构造完成之前,其他线程进入就会阻塞static LoggerManager eton;return eton;}void addLogger(Logger::ptr &logger){if(hasLogger(logger->name())) return;std::unique_lock<std::mutex> lock(_mutex);_loggers.insert(std::make_pair(logger->name(), logger));}bool hasLogger(const std::string name){std::unique_lock<std::mutex> lock(_mutex);auto it = _loggers.find(name);if(it == _loggers.end()){return false;}return true;}Logger::ptr getLogger(const std::string name){std::unique_lock<std::mutex> lock(_mutex);auto it = _loggers.find(name);if(it == _loggers.end()){return Logger::ptr();}return it->second;}Logger::ptr rootLogger(){return _root_logger;}private:// 构造函数私有化LoggerManager(){std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::LocalLoggerBuilder());builder->buildLoggerName("root");_root_logger = builder->build();_loggers.insert(std::make_pair("root", _root_logger));}private:std::mutex _mutex;Logger::ptr _root_logger; // 默认日志器std::unordered_map<std::string, Logger::ptr> _loggers // 日志器数组;};class GlobalLoggerBuilder : public LoggerBuilder{public:Logger::ptr build() override{assert(_logger_name.empty() == false);if (_formatter.get() == nullptr){_formatter = std::make_shared<Formatter>();}if (_sinks.empty()){buildSink<StdOutSink>();}Logger::ptr logger;if (_logger_type == LoggerType::LOGGER_ASYNC){logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);}else{logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);}LoggerManager::getInstance().addLogger(logger);return logger;}};
}#endif

日志器管理类测试

#include "logger.hpp"void log_test()
{LOG::Logger::ptr logger = LOG::LoggerManager::getInstance().getLogger("async_logger");logger->debug(__FILE__, __LINE__, "%s", "测试日志");logger->info(__FILE__, __LINE__, "%s", "测试日志");logger->warn(__FILE__, __LINE__, "%s", "测试日志");logger->error(__FILE__, __LINE__, "%s", "测试日志");logger->fatal(__FILE__, __LINE__, "%s", "测试日志");size_t count = 0;while(count < 300000){   logger->fatal(__FILE__, __LINE__, "测试日志-%d", count++);}
}
int main()
{   std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::GlobalLoggerBuilder());builder->buildLoggerName("async_logger");builder->buildLoggerLevel(LOG::LogLevel::value::WARN);builder->buildFormatter("[%c]%m%n");builder->buildLoggerType(LOG::LoggerType::LOGGER_ASYNC);builder->buildEnableUnSafeAsync();builder->buildSink<LOG::FileSink>("./logfile/async.log");builder->buildSink<LOG::StdOutSink>();builder->build();log_test();return 0;
}

在这里插入图片描述

相关文章:

C++项目实战——基于多设计模式下的同步异步日志系统-⑪-日志器管理类与全局建造者类设计(单例模式)

文章目录 专栏导读日志器建造者类完善单例日志器管理类设计思想单例日志器管理类设计全局建造者类设计日志器类、建造者类整理日志器管理类测试 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计…...

Hadoop3教程(十四):MapReduce中的排序

文章目录 &#xff08;99&#xff09;WritableComparable排序什么是排序什么时候需要排序排序有哪些分类如何实现自定义排序 &#xff08;100&#xff09;全排序案例案例需求思路分析实际代码 &#xff08;101&#xff09;二次排序案例&#xff08;102&#xff09; 区内排序案例…...

测试需要写测试用例吗?

如何理解软件的质量 我们都知道&#xff0c;一个软件从无到有要经过需求设计、编码实现、测试验证、部署发布这四个主要环节。 需求来源于用户反馈、市场调研或者商业判断。意指在市场行为中&#xff0c;部分人群存在某些诉求或痛点&#xff0c;只要想办法满足这些人群的诉求…...

Qt 视口和窗口的区别

视口和窗口 绘图设备的物理坐标是基本的坐标系&#xff0c;通过QPainter的平移、旋转等变换可以得到更容易操作的逻辑坐标 为了实现更方便的坐标&#xff0c;QPainter还提供了视口(Viewport)和窗口(Window)坐标系&#xff0c;通过QPainter内部的坐标变换矩阵自动转换为绘图设…...

使用Git将GitHub仓库下载到本地

前记&#xff1a; git svn sourcetree gitee github gitlab gitblit gitbucket gitolite gogs 版本控制 | 仓库管理 ---- 系列工程笔记. Platform&#xff1a;Windows 10 Git version&#xff1a;git version 2.32.0.windows.1 Function&#xff1a;使用Git将GitHub仓库下载…...

前端需要了解的浏览器缓存知识

文章目录 前言为什么需要缓存&#xff1f;DNS缓存缓存读写顺序缓存位置memory cache&#xff08;浏览器本地缓存&#xff09;disk cache&#xff08;硬盘缓存&#xff09;重点&#xff01;&#xff01;&#xff01; 缓存策略 - 强缓存和协商缓存1&#xff09;强缓存ExpiresCach…...

自动驾驶:控制算法概述

自动驾驶&#xff1a;控制算法概述 常见控制算法PID算法LQR算法MPC算法 自动驾驶控制算法横向控制纵向控制 参考文献 常见控制算法 PID算法 PID&#xff08;Proportional-Integral-Derivative&#xff09;控制是一种经典的反馈控制算法&#xff0c;通常用于稳定性和响应速度要…...

【Mysql】Mysql的字符集和比较规则(三)

字符集和比较规则简介 字符集简介 我们知道在计算机中只能以二进制的方式对数据进行存储&#xff0c;那么他们之间是怎样对应并进行转换的&#xff1f;我们需要了解两个概念&#xff1a; 字符范围&#xff1a;我们可以将哪些字符转换成二进制数据&#xff0c;也就是规定好字…...

【SpringCloud-11】SCA-sentinel

sentinel是一个流量控制、熔断降级的组件&#xff0c;可以替换第一代中的hystrix。 hystrix用起来没有那么方便&#xff1a; 1、要在调用方引入hystrix&#xff0c;没有ui界面进行配置&#xff0c;需要在代码中进行配置&#xff0c;侵入了业务代码。 2、还要自己搭建监控平台…...

设计模式:简单工厂模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):

简介&#xff1a; 简单工厂模式&#xff0c;它提供了一个用于创建对象的接口&#xff0c;但具体创建的对象类型可以在运行时决定。这种模式通常用于创建具有共同接口的对象&#xff0c;并且可以根据客户端代码中的参数或配置来选择要创建的具体对象类型。 在简单工厂模式中&am…...

浅谈智能照明控制系统在智慧建筑中的应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;新时期&#xff0c;建筑行业发展迅速&#xff0c;在信息化背景下&#xff0c;建筑功能逐渐拓展&#xff0c;呈现了智能化的发展态势。智能建筑更加安全、节能、环保&#xff0c;也符合绿色建筑理念。在建筑智…...

lower_bound()以及upper_bound()

lower_bound&#xff08;&#xff09;&#xff1a; lower_bound()的返回值是第一个大于等于 target 的值的地址&#xff0c;用这个地址减去first&#xff0c;得到的就是第一个大于等于target的值的下标。 在数组中&#xff1a; int poslower_bound(a,an,target)-a;\\n为数组…...

unity(WebGL) 截图拼接并保存本地,下载PDF

截图参考&#xff1a;Unity3D 局部截图、全屏截图、带UI截图三种方法_unity 截图_野区捕龙为宠的博客-CSDN博客 文档下载&#xff1a; Unity WebGL 生成doc保存到本地电脑_unity webgl 保存文件_野区捕龙为宠的博客-CSDN博客 中文输入&#xff1a;Unity WebGL中文输入 支持输…...

加速企业云计算部署:应对新时代的挑战

随着科技的飞速发展&#xff0c;企业面临着诸多挑战。在这个高度互联的世界中&#xff0c;企业的成功与否常常取决于其能否快速、有效地响应市场的变化。云计算作为一种新兴的技术趋势&#xff0c;为企业提供了实现这一目标的可能。通过加速企业云计算部署&#xff0c;企业可以…...

ubuntu 18.04 LTS交叉编译opencv 3.4.16并编译工程[全记录]

一、下载并解压opencv 3.4.16源码 https://opencv.org/releases/ 放到home路径下的Exe文件夹&#xff08;专门放用户安装的软件&#xff09;中&#xff0c;其中build是后期自建的 为了版本控制&#xff0c;保留了3.4.16&#xff0c;并增加了-gcc-arm 二、安装cmake和cmake-g…...

禁用和开启笔记本电脑的键盘功能,最快的方式

笔记本键盘通常较小&#xff0c;按键很不方便&#xff0c;当我们外接了键盘时就不需要再使用自带的键盘了&#xff0c;而且午睡的时候&#xff0c;总是担心碰到笔记本的键盘&#xff0c;可能会删掉我们的代码什么的&#xff0c;所以就想着怎么禁用掉&#xff0c;下面是操作步骤…...

【单片机基础】使用51单片机制作函数信号发生器(DAC0832使用仿真)

文章目录 &#xff08;1&#xff09;DA转换&#xff08;2&#xff09;DAC0832简介&#xff08;3&#xff09;电路设计&#xff08;4&#xff09;参考例程&#xff08;5&#xff09;参考文献 &#xff08;1&#xff09;DA转换 单片机作为一个数字电路系统&#xff0c;当需要采集…...

springcloud组件

https://www.bilibili.com/video/BV1QX4y1t7v5?p32&vd_source297c866c71fa77b161812ad631ea2c25 eureka : 主要是收集服务的注册信息。 如果有了eureka启动了。内部之前的调用其实就可以用服务名了&#xff0c; 本来是要是用ip端口来访问的&#xff0c;只要eureka启来了…...

手机爬虫用Appium详细教程:利用Python控制移动App进行自动化抓取数据

Appium是一个强大的跨平台工具&#xff0c;它可以让你使用Python来控制移动App进行自动化操作&#xff0c;从而实现数据的抓取和处理。今天&#xff0c;我将与大家分享一份关于使用Appium进行手机爬虫的详细教程&#xff0c;让我们一起来探索Appium的功能和操作&#xff0c;为手…...

deb包构建详解

deb包构建详解 一、deb包构建流程二、deb包构建描述文件详解2.1 control文件2.2 postinst 文件 (post-installation script)2.3 postrm 文件 (post-removal script)2.4 prerm 文件 (pre-removal script)2.5 preinst 文件 (pre-installation script)2.6 rules 文件2.7 changelog…...

hackGPT:基于大语言模型的智能命令行安全工具实践

1. 项目概述&#xff1a;当黑客工具遇上大语言模型最近在安全研究和自动化工具开发的圈子里&#xff0c;一个名为“hackGPT”的项目引起了我的注意。这个由NoDataFound开源的仓库&#xff0c;名字本身就充满了噱头——它将“黑客”&#xff08;hack&#xff09;与当下最热的大语…...

从零开始在个人项目中接入Taotoken的完整步骤与体会

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 从零开始在个人项目中接入Taotoken的完整步骤与体会 最近在维护一个个人开发的智能写作助手项目&#xff0c;最初直接使用了某家模…...

气体放电管实战指南:从关键参数到电路防护的精准匹配

1. 气体放电管&#xff1a;电路防护的"安全气囊" 第一次接触气体放电管时&#xff0c;我就被它简单却巧妙的设计所吸引。这玩意儿就像汽车的安全气囊——平时默默无闻&#xff0c;关键时刻却能救你一命。气体放电管&#xff08;GDT&#xff09;本质上是个陶瓷或玻璃…...

JAVA低空经济无人机飞手接单平台系统源码开发与部署方案

随着低空经济产业的快速发展&#xff0c;无人机应用场景不断拓展&#xff0c;航拍、测绘、巡检、物流等领域对专业飞手的需求日益增长&#xff0c;飞手接单难、需求方找飞手繁琐的行业痛点愈发突出。一、系统开发核心原则&#xff08;务实合规&#xff0c;贴合场景&#xff09;…...

无感定位技术白皮书——传统ReID跨镜跟踪局限重重,无短板碾压式突破

前言在智慧安防、智慧园区、工业物联网等数字化转型核心场景中&#xff0c;跨摄像头目标追踪与精准定位是支撑场景智能化升级的关键底座。长期以来&#xff0c;ReID&#xff08;行人重识别&#xff09;技术因无需额外硬件部署、可依托目标外观特征实现跨镜身份关联&#xff0c;…...

Exynos 5410处理器:big.LITTLE架构与28nm工艺的移动计算革命

1. Exynos 5410处理器&#xff1a;移动计算的新标杆2013年&#xff0c;当智能手机和平板电脑的性能需求开始爆发式增长时&#xff0c;三星推出了Exynos 5410处理器&#xff0c;这款SoC在当时堪称移动计算领域的一次革命。作为全球首款采用big.LITTLE架构的八核处理器&#xff0…...

从计数器到计时器:使用Spectator构建可观测性系统的实践指南

1. 项目概述&#xff1a;从“观众”到“观察者”的视角转变在软件开发&#xff0c;尤其是后端服务开发中&#xff0c;我们常常需要一种机制来观察和度量系统的内部状态。这种观察不是简单的日志打印&#xff0c;而是系统化、结构化地收集运行时指标&#xff0c;比如接口的调用次…...

Proxima向量检索库:硬件优化与量化技术实战解析

1. 项目概述&#xff1a;一个为现代开发者打造的“近邻”代码库 最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“Zen4-bit/Proxima”。乍一看这个标题&#xff0c;可能会有点摸不着头脑。“Zen4-bit”像是一个用户名或者某种架构的代号&#xff0c;而“Proxima”则让人联…...

大语言模型对抗性攻击与防御:Decepticon框架原理与实践

1. 项目概述&#xff1a;当AI学会“伪装”&#xff0c;一场攻防博弈的新范式最近在安全圈和AI研究领域&#xff0c;一个名为“Decepticon”的项目引起了我的注意。这个项目来自PurpleAILAB&#xff0c;名字本身就充满了对抗的意味——“Decepticon”直译是“霸天虎”&#xff0…...

子网掩码实战:从原理到网络规划的深度解析

1. 子网掩码的核心原理 第一次接触子网掩码时&#xff0c;我也被那一串数字搞得晕头转向。直到有次公司网络改造&#xff0c;亲眼看到老工程师用子网划分解决了IP地址不足的问题&#xff0c;才真正明白它的价值。简单来说&#xff0c;子网掩码就像邮局的邮政编码系统 - 它告诉网…...