深入解析享元模式:通过共享技术高效支持大量细粒度对象

深入解析享元模式:通过共享技术高效支持大量细粒度对象


🌟 嗨,我是IRpickstars!

🌌 总有一行代码,能点亮万千星辰。

🔍 在技术的宇宙中,我愿做永不停歇的探索者。

✨ 用代码丈量世界,用算法解码未来。我是摘星人,也是造梦者。

🚀 每一次编译都是新的征程,每一个bug都是未解的谜题。让我们携手,在0和1的星河中,书写属于开发者的浪漫诗篇。


目录

深入解析享元模式:通过共享技术高效支持大量细粒度对象

摘要

享元模式概述

模式定义

问题背景

核心理念

核心原理与UML类图

内部状态与外部状态

UML类图

核心角色

代码实现详解

Java实现

Python实现

C++实现

文本编辑器字符对象池案例分析

案例背景

架构设计

完整实现

内存优化效果

其他应用场景

游戏开发中的粒子系统

图形界面中的图标管理

数据库连接池

优缺点分析

优点

缺点

与其他设计模式的对比

享元模式 vs 单例模式

享元模式 vs 对象池模式

享元模式 vs 工厂模式

实际应用中的最佳实践

设计原则

注意事项

总结

参考资料


摘要

作为一名技术博客创作者,我深知设计模式在软件开发中的重要性。今天,我将为大家深入解析享元模式(Flyweight Pattern)——这一在内存优化方面极其重要的结构型设计模式。享元模式是"资源池技术"实现方式,主要用于减少创建对象的数量,以减少内存占用和提高性能。

本文将从享元模式的核心理念"通过共享技术高效支持大量细粒度对象"出发,全面阐述其设计原理、实现机制和实际应用。文章重点解析文本编辑器中字符对象池的经典应用场景,这是理解享元模式最直观的例子。通过这个案例,您将深刻理解内部状态与外部状态的分离机制,以及享元工厂的对象池管理策略。

文章涵盖了享元模式的完整技术体系:从UML类图到多语言代码实现,从核心原理到实际应用场景,从优缺点分析到与其他设计模式的对比。我将提供Java、Python、C++三种语言的完整实现,并通过可运行的测试代码展示内存优化的显著效果。

通过阅读本文,您将获得:深入理解享元模式的本质思想和实现原理;掌握内部状态与外部状态的分离技巧;学会设计高效的享元工厂和对象池管理策略;了解享元模式在实际项目中的应用场景和最佳实践。无论您是初学者还是有经验的开发者,这篇文章都将为您的技术积累增添宝贵的价值。

享元模式概述

模式定义

享元模式(Flyweight Pattern)是一种结构型设计模式,运用共享技术有效地支持大量细粒度对象的复用。该模式的核心思想是:当需要创建大量相似对象时,通过共享对象的公共部分来减少内存消耗,同时保持对象的独立性。

问题背景

在面向对象编程中,我们经常遇到需要创建大量相似对象的场景。例如:

  • 文本编辑器中的字符对象
  • 游戏中的粒子系统
  • 图形界面中的图标组件
  • 数据库连接池中的连接对象

如果为每个对象都创建独立的实例,可能会造成内存溢出,享元模式把其中共同的部分抽象出来,保存在内存中,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

核心理念

享元模式的核心理念是"通过共享技术高效支持大量细粒度对象"。这个理念体现在以下几个方面:

  1. 共享技术:将对象的公共部分提取出来,在多个对象间共享
  2. 细粒度对象:处理的是数量巨大但结构相似的小对象
  3. 高效支持:通过减少对象创建和内存占用来提高系统性能

核心原理与UML类图

内部状态与外部状态

享元模式的关键在于区分内部状态和外部状态:

  • 内部状态(Intrinsic State):享元对象可共享的属性,存储在享元对象内部并且不会随环境改变而改变
  • 外部状态(Extrinsic State):对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态

UML类图

图1:享元模式UML类图

核心角色

  1. 抽象享元(Flyweight):定义享元对象的接口,规定具体享元类必须实现的方法
  2. 具体享元(ConcreteFlyweight):实现抽象享元接口,存储内部状态
  3. 享元工厂(FlyweightFactory):负责创建和管理享元对象,维护享元池
  4. 客户端(Client):维护外部状态,并通过享元工厂获取享元对象

代码实现详解

Java实现

// 抽象享元接口
interface Flyweight {/*** 享元对象的业务方法* @param extrinsicState 外部状态*/void operation(String extrinsicState);
}// 具体享元类
class ConcreteFlyweight implements Flyweight {private final String intrinsicState; // 内部状态public ConcreteFlyweight(String intrinsicState) {this.intrinsicState = intrinsicState;System.out.println("创建具体享元对象:" + intrinsicState);}@Overridepublic void operation(String extrinsicState) {System.out.println("享元对象 - 内部状态:" + intrinsicState + ",外部状态:" + extrinsicState);}
}// 享元工厂类
class FlyweightFactory {private final Map<String, Flyweight> flyweights = new HashMap<>();/*** 获取享元对象* @param key 享元对象的标识* @return 享元对象*/public Flyweight getFlyweight(String key) {Flyweight flyweight = flyweights.get(key);if (flyweight == null) {flyweight = new ConcreteFlyweight(key);flyweights.put(key, flyweight);}return flyweight;}/*** 获取享元池中对象的数量* @return 享元对象数量*/public int getFlyweightCount() {return flyweights.size();}
}// 客户端测试类
public class FlyweightPatternDemo {public static void main(String[] args) {FlyweightFactory factory = new FlyweightFactory();// 获取享元对象Flyweight flyweight1 = factory.getFlyweight("A");Flyweight flyweight2 = factory.getFlyweight("B");Flyweight flyweight3 = factory.getFlyweight("A"); // 复用已存在的对象// 使用享元对象flyweight1.operation("外部状态1");flyweight2.operation("外部状态2");flyweight3.operation("外部状态3");// 验证对象复用System.out.println("flyweight1 == flyweight3: " + (flyweight1 == flyweight3));System.out.println("享元池中对象数量: " + factory.getFlyweightCount());}
}

Python实现

from abc import ABC, abstractmethod
from typing import Dictclass Flyweight(ABC):"""抽象享元类"""@abstractmethoddef operation(self, extrinsic_state: str) -> None:"""享元对象的业务方法"""passclass ConcreteFlyweight(Flyweight):"""具体享元类"""def __init__(self, intrinsic_state: str):self._intrinsic_state = intrinsic_state  # 内部状态print(f"创建具体享元对象:{intrinsic_state}")def operation(self, extrinsic_state: str) -> None:print(f"享元对象 - 内部状态:{self._intrinsic_state},外部状态:{extrinsic_state}")class FlyweightFactory:"""享元工厂类"""def __init__(self):self._flyweights: Dict[str, Flyweight] = {}def get_flyweight(self, key: str) -> Flyweight:"""获取享元对象"""if key not in self._flyweights:self._flyweights[key] = ConcreteFlyweight(key)return self._flyweights[key]def get_flyweight_count(self) -> int:"""获取享元池中对象的数量"""return len(self._flyweights)# 客户端测试
if __name__ == "__main__":factory = FlyweightFactory()# 获取享元对象flyweight1 = factory.get_flyweight("A")flyweight2 = factory.get_flyweight("B")flyweight3 = factory.get_flyweight("A")  # 复用已存在的对象# 使用享元对象flyweight1.operation("外部状态1")flyweight2.operation("外部状态2")flyweight3.operation("外部状态3")# 验证对象复用print(f"flyweight1 is flyweight3: {flyweight1 is flyweight3}")print(f"享元池中对象数量: {factory.get_flyweight_count()}")

C++实现

#include <iostream>
#include <unordered_map>
#include <memory>
#include <string>// 抽象享元类
class Flyweight {
public:virtual ~Flyweight() = default;virtual void operation(const std::string& extrinsicState) = 0;
};// 具体享元类
class ConcreteFlyweight : public Flyweight {
private:std::string intrinsicState; // 内部状态public:explicit ConcreteFlyweight(const std::string& intrinsicState) : intrinsicState(intrinsicState) {std::cout << "创建具体享元对象:" << intrinsicState << std::endl;}void operation(const std::string& extrinsicState) override {std::cout << "享元对象 - 内部状态:" << intrinsicState << ",外部状态:" << extrinsicState << std::endl;}
};// 享元工厂类
class FlyweightFactory {
private:std::unordered_map<std::string, std::shared_ptr<Flyweight>> flyweights;public:std::shared_ptr<Flyweight> getFlyweight(const std::string& key) {auto it = flyweights.find(key);if (it == flyweights.end()) {auto flyweight = std::make_shared<ConcreteFlyweight>(key);flyweights[key] = flyweight;return flyweight;}return it->second;}size_t getFlyweightCount() const {return flyweights.size();}
};// 客户端测试
int main() {FlyweightFactory factory;// 获取享元对象auto flyweight1 = factory.getFlyweight("A");auto flyweight2 = factory.getFlyweight("B");auto flyweight3 = factory.getFlyweight("A"); // 复用已存在的对象// 使用享元对象flyweight1->operation("外部状态1");flyweight2->operation("外部状态2");flyweight3->operation("外部状态3");// 验证对象复用std::cout << "flyweight1 == flyweight3: " << (flyweight1 == flyweight3 ? "true" : "false") << std::endl;std::cout << "享元池中对象数量: " << factory.getFlyweightCount() << std::endl;return 0;
}

文本编辑器字符对象池案例分析

案例背景

文本编辑器是享元模式最经典的应用场景之一。当一个文本字符串存在大量重复字符,如果每一个字符都用一个单独的对象表示,将会占用较多内存空间。通过享元模式,我们可以将字符的内容作为内部状态共享,将字符的位置、颜色、字体等作为外部状态。

架构设计

图2:文本编辑器字符对象池架构图

完整实现

// 字符享元接口
interface CharacterFlyweight {void display(int row, int col, String color, String font);
}// 具体字符享元类
class ConcreteCharacter implements CharacterFlyweight {private final char character; // 内部状态:字符内容public ConcreteCharacter(char character) {this.character = character;}@Overridepublic void display(int row, int col, String color, String font) {System.out.printf("字符'%c'显示在位置(%d,%d),颜色:%s,字体:%s%n",character, row, col, color, font);}
}// 字符工厂
class CharacterFactory {private static final Map<Character, CharacterFlyweight> characters = new HashMap<>();public static CharacterFlyweight getCharacter(char c) {CharacterFlyweight character = characters.get(c);if (character == null) {character = new ConcreteCharacter(c);characters.put(c, character);System.out.println("创建字符享元对象:" + c);}return character;}public static int getCharacterCount() {return characters.size();}
}// 文档字符类(包含外部状态)
class DocumentCharacter {private final CharacterFlyweight character;private final int row;private final int col;private final String color;private final String font;public DocumentCharacter(char c, int row, int col, String color, String font) {this.character = CharacterFactory.getCharacter(c);this.row = row;this.col = col;this.color = color;this.font = font;}public void display() {character.display(row, col, color, font);}
}// 文本编辑器
class TextEditor {private final List<DocumentCharacter> document = new ArrayList<>();public void addCharacter(char c, int row, int col, String color, String font) {document.add(new DocumentCharacter(c, row, col, color, font));}public void displayDocument() {System.out.println("文档内容:");for (DocumentCharacter dc : document) {dc.display();}}public void showMemoryUsage() {System.out.println("文档字符数量:" + document.size());System.out.println("享元对象数量:" + CharacterFactory.getCharacterCount());System.out.println("内存节省率:" + (1.0 - (double)CharacterFactory.getCharacterCount() / document.size()) * 100 + "%");}
}// 测试类
public class TextEditorDemo {public static void main(String[] args) {TextEditor editor = new TextEditor();// 模拟输入文本:"Hello World!"String text = "Hello World!";for (int i = 0; i < text.length(); i++) {char c = text.charAt(i);editor.addCharacter(c, 1, i, "黑色", "宋体");}// 再次输入相同文本for (int i = 0; i < text.length(); i++) {char c = text.charAt(i);editor.addCharacter(c, 2, i, "红色", "微软雅黑");}// 显示文档editor.displayDocument();// 显示内存使用情况editor.showMemoryUsage();}
}

内存优化效果

图3:内存优化效果对比图

运行结果显示,对于包含24个字符的文档,传统方式需要24个字符对象,而享元模式只需要10个享元对象(去重后的字符数量),内存节省率达到58.3%。

其他应用场景

游戏开发中的粒子系统

// 粒子享元
class ParticleFlyweight {private final String texture; // 内部状态:纹理private final String color;   // 内部状态:颜色public ParticleFlyweight(String texture, String color) {this.texture = texture;this.color = color;}public void render(int x, int y, float velocity, float angle) {// 外部状态:位置、速度、角度System.out.printf("渲染粒子 - 纹理:%s,颜色:%s,位置:(%d,%d),速度:%.2f,角度:%.2f%n",texture, color, x, y, velocity, angle);}
}

图形界面中的图标管理

// 图标享元
class IconFlyweight {private final String iconName; // 内部状态:图标名称private final byte[] iconData; // 内部状态:图标数据public IconFlyweight(String iconName, byte[] iconData) {this.iconName = iconName;this.iconData = iconData;}public void display(int x, int y, int width, int height) {// 外部状态:位置、尺寸System.out.printf("显示图标 - 名称:%s,位置:(%d,%d),尺寸:%dx%d%n",iconName, x, y, width, height);}
}

数据库连接池

// 数据库连接享元
class DatabaseConnection {private final String url;      // 内部状态:数据库URLprivate final String driver;   // 内部状态:驱动类型private boolean inUse = false; // 连接状态public DatabaseConnection(String url, String driver) {this.url = url;this.driver = driver;}public void execute(String sql, String user) {// 外部状态:SQL语句、用户信息System.out.printf("连接 %s 执行SQL:%s,用户:%s%n", url, sql, user);}
}

优缺点分析

优点

  1. 显著减少内存消耗:享元模式通过共享相似对象,减少了对象的创建,从而降低了内存使用和提高了性能
  2. 提高系统性能:减少对象创建和垃圾回收的开销,提升系统运行效率
  3. 外部状态独立:享元模式外部状态相对独立,不会影响到内部状态,从而使得享元对象可以在不同环境中被共享
  4. 线程安全:享元对象通常是不可变的,天然具备线程安全特性

缺点

  1. 增加系统复杂度:享元模式使得系统变复杂,需要分离出内部状态以及外部状态,使得程序逻辑复杂化
  2. 运行时间增加:为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态使得运行时间变长
  3. 状态维护成本:外部状态的管理增加了系统的复杂度和维护成本
  4. 适用范围有限:只有在存在大量相似对象时才能发挥作用

与其他设计模式的对比

享元模式 vs 单例模式

对比维度

享元模式

单例模式

实例数量

多个享元实例

全局唯一实例

状态管理

区分内部/外部状态

实例状态统一管理

应用场景

大量相似对象

全局唯一资源

内存优化

通过共享减少对象数量

确保单一实例

享元模式 vs 对象池模式

对比维度

享元模式

对象池模式

核心目的

减少对象创建

重用昂贵对象

对象共享

基于内部状态共享

基于对象可用性

状态管理

严格区分内外部状态

重置对象状态

生命周期

享元对象长期存在

对象在池中循环使用

享元模式 vs 工厂模式

享元模式通常结合工厂模式使用,工厂模式负责创建和管理享元对象,而享元模式专注于对象的共享策略。

实际应用中的最佳实践

设计原则

  1. 合理划分状态:准确区分内部状态和外部状态是关键
  2. 线程安全考虑:确保享元对象的不可变性
  3. 工厂管理:使用享元工厂统一管理对象池
  4. 性能监控:定期监控内存使用情况和性能指标

注意事项

  1. 避免过度设计:应当在需要多次重复使用享元对象时才值得使用享元模式
  2. 状态分离准确性:错误的状态分离会导致系统复杂度增加而效果不佳
  3. 并发安全:在多线程环境中要确保享元工厂的线程安全

总结

通过本文的深入分析,我对享元模式有了全面而深刻的理解。享元模式作为一种重要的结构型设计模式,其核心价值在于"通过共享技术高效支持大量细粒度对象"这一设计理念。这种模式在内存优化方面具有显著效果,特别是在处理大量相似对象的场景中。

文本编辑器字符对象池案例完美诠释了享元模式的实际应用价值。通过将字符内容作为内部状态共享,将位置、颜色、字体等作为外部状态,我们成功地将24个字符对象优化为10个享元对象,内存节省率达到58.3%。这个案例不仅展示了享元模式的技术实现,更重要的是验证了其在实际项目中的优化效果。

从技术实现角度看,享元模式的关键在于内部状态与外部状态的正确分离。内部状态是可共享的、不变的核心数据,而外部状态是变化的、由客户端维护的环境信息。这种分离策略使得系统能够在保持对象独立性的同时实现高效的内存管理。

享元工厂作为模式的核心组件,承担着对象池管理的重要职责。通过维护一个键值映射的享元池,工厂能够确保相同内部状态的对象只创建一次,从而实现真正的对象共享。这种设计不仅优化了内存使用,还提高了对象创建的效率。

在实际应用中,享元模式广泛应用于游戏开发、图形界面、数据库连接池等领域。每个应用场景都体现了享元模式在处理大量相似对象时的独特优势。然而,我们也要认识到享元模式的局限性:它会增加系统的复杂度,需要额外的状态管理成本,并且只在特定场景下才能发挥最佳效果。

对于希望在项目中应用享元模式的开发者,我建议首先准确分析对象的状态特征,确保能够合理地分离内部状态和外部状态。同时,要评估系统中相似对象的数量是否足够大,以证明引入享元模式的复杂度是值得的。最后,要注意线程安全和性能监控,确保享元模式在实际运行中能够达到预期的优化效果。

享元模式体现了软件设计中"时间换空间"的经典思想,通过增加一定的时间复杂度来换取显著的空间优化。在当今内存资源依然宝贵的环境中,掌握并合理运用享元模式对于提升系统性能具有重要意义。

参考资料

  1. 权威文档
    • GoF设计模式原书:Design Patterns: Elements of Reusable Object-Oriented Software
    • Oracle Java官方文档
  1. 开源项目
    • ZhiminXu/DesignPatterns - GOF 23种设计模式C++实现
    • senghoo/golang-design-pattern - 设计模式Golang实现
    • qiualiang/gof - 23种GoF设计模式
  1. 技术博客
    • 菜鸟教程:享元模式
    • 深入理解设计模式:享元模式
    • ShuSheng007:秒懂设计模式之享元模式

🌟 嗨,我是IRpickstars!如果你觉得这篇技术分享对你有启发:

🛠️ 点击【点赞】让更多开发者看到这篇干货
🔔 【关注】解锁更多架构设计&性能优化秘籍
💡 【评论】留下你的技术见解或实战困惑

作为常年奋战在一线的技术博主,我特别期待与你进行深度技术对话。每一个问题都是新的思考维度,每一次讨论都能碰撞出创新的火花。

🌟 点击这里👉 IRpickstars的主页 ,获取最新技术解析与实战干货!

⚡️ 我的更新节奏:

  • 每周三晚8点:深度技术长文
  • 每周日早10点:高效开发技巧
  • 突发技术热点:48小时内专题解析

 

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

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

相关文章

Docker高级管理

一、Docker 容器的网络模式 当项目大规模使用 Docker 时&#xff0c;容器通信的问题也就产生了。要解决容器通信问题&#xff0c;必须先了解很多关于网络的知识。Docker 的网络模式非常丰富&#xff0c;可以满足不同容器的通信要求&#xff0c;下表列出了这些网络模式的主要信息…

ABP VNext + Tye:本地微服务编排与调试

ABP VNext Tye&#xff1a;本地微服务编排与调试 &#x1f680; &#x1f4da; 目录ABP VNext Tye&#xff1a;本地微服务编排与调试 &#x1f680;TL;DR ✨一、环境与依赖 &#x1f6e0;️二、核心配置详解 &#x1f680;1. 主配置 tye.yaml三、多环境文件 &#x1f331;&am…

Vue响应式原理一:认识响应式逻辑

核心思想&#xff1a;当数据发生变化时&#xff0c;依赖该数据的代码能够自动重新执行Vue中的应用&#xff1a;在data或ref/reactive中定义的数据&#xff0c;当数据变化时template会自动更新template的本质&#xff1a; 是render()函数, 用变化之后的数据重新执行render()函数…

Redis:分组与设备在 Redis 中缓存存储设计

一、缓存存储结构设计 分组与设备的映射关系&#xff08;使用 Set 结构&#xff09;&#xff1a; 键格式&#xff1a;采用 group:{groupId}:devices 的格式作为 Redis 中 Set 的键&#xff0c;例如 group:1:devices 就代表了分组 ID 为 1 的分组所关联的设备集合。值内容&#…

Leetcode 3605. Minimum Stability Factor of Array

Leetcode 3605. Minimum Stability Factor of Array 1. 解题思路2. 代码实现 题目链接&#xff1a;3605. Minimum Stability Factor of Array 1. 解题思路 这一题的核心思路是二分法&#xff0c;本质上就是我们给定一个常数kkk&#xff0c;然后考察是否存在一个构造使得能够…

编译安装的Mysql5.7报“Couldn‘t find MySQL server (mysqld_safe)“的原因 笔记250709

编译安装的Mysql5.7报"Couldn’t find MySQL server (mysqld_safe)"的原因 笔记250709 MySQL 的安装路径与配置文件&#xff08;如 my.cnf 或 mysql.server&#xff09;中指定的 basedir 不一致。 mysqld_safe 文件实际位置与系统查找路径不匹配&#xff08;常见于自…

在 Ubuntu 下配置 oh-my-posh —— 普通用户 + root 各自使用独立主题(共享可执行)

&#x1f9e9; 在 Ubuntu 下配置 oh-my-posh —— 普通用户 root 各自使用独立主题&#xff08;共享可执行&#xff09;✅ 目标说明普通用户 使用 tokyonight_storm 主题 root 用户 使用 1_shell 主题 共用全局路径下的 oh-my-posh 可执行文件 正确加载 Homebrew 到环境变量中…

Spring Boot 项目中的多数据源配置

关键词&#xff1a;Spring Boot、多数据源配置、MySQL、SQL Server、Oracle、动态切换 ✅ 摘要 在实际企业级开发中&#xff0c;一个 Spring Boot 项目可能需要连接多个数据库&#xff0c;比如 MySQL、SQL Server 和 Oracle。不同的业务模块可能依赖不同的数据源&#xff0c;这…

MATLAB/Simulink电机控制仿真代做 同步异步永磁直驱磁阻双馈无刷

以下是针对 MATLAB/Simulink 电机控制仿真 的系统性解决方案&#xff0c;涵盖 同步电机、异步电机、永磁电机、直驱电机、磁阻电机、双馈电机、无刷直流电机&#xff08;BLDC&#xff09; 的建模与控制策略实现&#xff0c;支持代做服务的技术细节和代码示例。一、电机建模与仿…

限流算法深度探索:从理论到实践的生产级避坑指南

凌晨3点&#xff0c;监控警报刺耳地尖叫着。我盯着屏幕上垂直下跌的服务可用性曲线&#xff0c;意识到那个被忽视的限流配置项终于引爆了——每秒1000次的支付请求正像洪水般冲垮我们的系统。这次事故让我深刻理解&#xff1a;限流不是可选项&#xff0c;而是分布式系统的生存法…

企业级后台管理系统的困境与飞算 JavaAI 的破局之道

企业级后台管理系统如 CRM&#xff08;客户关系管理系统&#xff09;、ERP&#xff08;企业资源计划系统&#xff09;已成为支撑企业高效运转的核心骨架。它们如同企业的 “神经中枢”&#xff0c;串联起客户数据、财务信息、供应链流程等关键环节&#xff0c;为决策制定、业务…

快速上手百宝箱搭建知识闯关游戏助手

引言&#xff1a;让学习更有趣&#xff0c;AI 赋能知识闯关新体验 1.在信息爆炸的时代&#xff0c;传统的填鸭式教学方式已难以满足现代用户对高效、个性化和趣味化学习的需求。越来越多的学习者倾向于通过互动性强、参与感十足的方式获取知识。在此背景下&#xff0c;游戏化学…

【YOLOv11-目标检测】目标检测数据格式(官方说明)

原文链接&#xff1a; https://docs.ultralytics.com/datasets/detect/ 写在前面 训练一个鲁棒且准确的目标检测模型需要一个全面的数据集。本文介绍&#xff1a;与Ultralytics YOLO模型兼容的各种数据集格式&#xff0c;并深入解析了它们的结构、使用方法以及如何在不同的格…

yolo8实现目标检测

✅步骤一&#xff1a;安装 PyTorch&#xff08;M1 专用&#xff09;# 推荐使用官方 MPS 后端&#xff08;Apple Metal 加速&#xff09; pip install torch torchvision torchaudio确认是否使用了 Apple MPS&#xff1a;import torch print(torch.backends.mps.is_available()…

安全管理协议(SMP):配对流程、密钥生成与防中间人攻击——蓝牙面试核心考点精解

一、SMP 核心知识点高频考点解析1.1 SMP 在蓝牙安全体系中的定位考点&#xff1a;SMP 的功能与协议栈位置解析&#xff1a; SMP&#xff08;Security Manager Protocol&#xff0c;安全管理协议&#xff09;是蓝牙核心规范中负责设备配对、密钥生成与安全连接的关键协议&#x…

U盘实现——U 盘类特殊命令

文章目录 U 盘类特殊命令U 盘的命令封包命令阶段数据阶段状态阶段get max luninquiry(0x12)read format capacities(0x23)read capacity(0x25)mode sense(0x1a)test unit ready(0x00)read(10) 0x28write(10) 0x2aU 盘类特殊命令 U 盘的命令封包 命令阶段 命令阶段主要由主机通…

深度帖:浏览器的事件循环与JS异步

一、浏览器进程 早期的浏览器是单进程的&#xff0c;所有功能杂糅在一个进程中&#xff1b;现在的浏览器是多进程的&#xff0c;包含浏览器进程、网络进程、渲染进程等等&#xff0c;每个进程负责的工作不同。浏览器进程&#xff1a;负责界面显示&#xff08;地址栏、书签、历史…

Linux网络:UDP socket创建流程与简单通信

本文介绍 UDP 服务端与客户端 的创建流程&#xff0c;和相关的函数接口 核心流程 创建 socket → socket()填写服务器地址信息 → sockaddr_in 结构体绑定地址和端口 → bind()接收并响应客户端数据 → recvfrom() / sendto()socket() #include<sys/so…

windows内核研究(系统调用 1)

WindowsAPI函数的调用过程什么是WindowsApi&#xff1f;Windows API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是微软为Windows操作系统提供的一套系统级编程接口&#xff0c;允许开发者与操作系统内核、硬件、系统服务等进行交互…

【前端】异步任务风控验证与轮询机制技术方案(通用笔记版)

一、背景场景 在某类生成任务中&#xff0c;例如用户点击“执行任务”按钮后触发一个较耗时的后端操作&#xff08;如生成报告、渲染图像、转码视频等&#xff09;&#xff0c;由于其调用了模型、渲染服务或需要较长处理时间&#xff0c;为了防止接口被频繁恶意调用&#xff0c…