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

无锁队列设计

无锁队列设计文章目录无锁队列设计1. 为什么需要无锁队列2. 无锁编程基本概念2.1 阻塞Blocking、无锁Lock-Free与无等待Wait-Free2.2 无锁编程的挑战3. 无锁队列的分类4. SPSC环形缓冲区实现4.1 基本设计要点4.2 ringBuffer实现带详细注释4.3 关键点解析5. MPSC链表实现5.1 设计思路5.2 非侵入式实现5.3 侵入式实现6. 无锁队列设计中的考虑6.1 内存序的正确选择6.2 内存管理6.4 性能调优7. 性能对比与适用场景8. 总结在多线程编程中队列是一种常用的数据结构用于在生产者和消费者之间传递数据。然而传统的基于锁的队列在高并发场景下会引入性能瓶颈线程阻塞、上下文切换、缓存行失效等。无锁队列Lock-Free Queue通过原子操作和精心设计的数据结构避免了锁的开销在某些场景下能大幅提升性能。本文将深入探讨无锁队列的设计思想、常见实现及注意事项。1. 为什么需要无锁队列多线程环境下的锁竞争会带来以下问题线程切换开销当锁被持有时其他线程必须等待操作系统可能进行上下文切换耗时可达微秒级。缓存损坏Cache Pollution锁的争用会导致内核调度器干预使CPU缓存失效后续重新加载数据需要时间。任务执行时间不确定在硬实时系统或信号处理程序中无法容忍阻塞等待。优先级反转低优先级线程持有锁高优先级线程等待可能导致系统不可预测。无锁队列允许多个线程并发访问而不使用互斥锁通过原子操作如CAS、Exchange来保证数据一致性从而避免上述问题。2. 无锁编程基本概念2.1 阻塞Blocking、无锁Lock-Free与无等待Wait-Free阻塞Blocking使用互斥锁、信号量等同步机制线程在无法获取资源时会进入休眠由操作系统调度唤醒。无锁Lock-Free整个系统的整体进度有保证即任意线程被暂停其他线程仍能继续完成操作。通常通过原子操作实现但单个线程可能面临重试如CAS失败。无等待Wait-Free在无锁的基础上更进一步保证每个线程的操作在有限步内完成不会因为其他线程的干扰而无限重试。实现难度极高。2.2 无锁编程的挑战内存管理在多生产者多消费者场景下如何安全释放节点内存常用技术有Hazard Pointer、RCU读-复制-更新、引用计数等。内存顺序Memory Ordering原子操作需要配合恰当的内存顺序如memory_order_acquire/release/relaxed以保证跨线程的可见性和有序性。3. 无锁队列的分类根据生产者和消费者的数量无锁队列可分为类型全称适用场景SPSCSingle Producer Single Consumer单一生产者和单一消费者实现最简单性能最高SPMCSingle Producer Multiple Consumers单一生产者多个消费者较少见MPSCMultiple Producers Single Consumer多个生产者单一消费者如日志收集、任务分发MPMCMultiple Producers Multiple Consumers多个生产者多个消费者通用但实现复杂本文将重点讲解SPSC环形缓冲区和MPSC链表队列的实现。4. SPSC环形缓冲区实现环形缓冲区Ring Buffer基于固定大小的数组通过头尾索引实现FIFO。SPSC场景下生产者和消费者分别操作tail_和head_索引通过原子操作保证线程安全。4.1 基本设计要点数组容量设为2的幂次以便将取模运算优化为位与运算next (curr 1) (cap - 1)。存储任意类型使用std::aligned_storage预留内存通过placement new构造/析构对象支持非POD类型。伪共享False Sharing将head_、tail_和缓冲区数据放在不同的缓存行通常64字节避免频繁同步导致性能下降。内存序利用memory_order_acquire/release保证写操作在消费者读之前可见且读操作能看到最新的写入。4.2 ringBuffer实现带详细注释#pragmaonce#includeatomic#includeutility// std::forward#includecstddef// std::size_t// SPSC 环形缓冲区容量必须为2的幂templatetypenameT,std::size_t CapacityclassringBuffer{public:static_assert(Capacity((Capacity(Capacity-1))0),Capacity must be a power of 2);ringBuffer():head_(0),tail_(0){}~ringBuffer(){// 析构时若队列中还有未消费的元素需要手动调用析构函数std::size_t headhead_.load(std::memory_order_relaxed);std::size_t tailtail_.load(std::memory_order_relaxed);while(head!tail){reinterpret_castT*(buffer_[head])-~T();head(head1)(Capacity-1);}}// 万能引用支持左值和右值templatetypenameUboolPush(Uvalue){std::size_t tailtail_.load(std::memory_order_relaxed);std::size_t next_tail(tail1)(Capacity-1);// 检查队列是否满下一个tail位置等于head表示无空位if(next_tailhead_.load(std::memory_order_acquire)){returnfalse;// 队列满}// 在缓冲区尾部构造对象placement newnew(buffer_[tail])T(std::forwardU(value));// 更新tail使用release语义确保之前的构造对其他线程可见tail_.store(next_tail,std::memory_order_release);returntrue;}boolPop(Tvalue){std::size_t headhead_.load(std::memory_order_relaxed);if(headtail_.load(std::memory_order_acquire)){returnfalse;// 队列空}// 移动取出元素使用move优化避免拷贝valuestd::move(*reinterpret_castT*(buffer_[head]));// 显式析构对象reinterpret_castT*(buffer_[head])-~T();// 更新head使用release语义保证之前的析构和移动操作对其他线程可见head_.store((head1)(Capacity-1),std::memory_order_release);returntrue;}// 返回当前队列中元素个数注意非原子快照仅用于调试std::size_tSize()const{conststd::size_t headhead_.load(std::memory_order_relaxed);conststd::size_t tailtail_.load(std::memory_order_relaxed);returntailhead?tail-head:Capacity-(head-tail);}private:// 将head_和tail_各自对齐到64字节避免与buffer_共享缓存行alignas(64)std::atomicstd::size_thead_;alignas(64)std::atomicstd::size_ttail_;// 存储元素的原始内存保证对齐alignas(64)std::aligned_storage_tsizeof(T),alignof(T)buffer_[Capacity];};4.3 关键点解析容量为2的幂(tail 1) (Capacity - 1)等价于(tail 1) % Capacity但位运算更快。内存对齐alignas(64)强制将变量放在64字节边界避免与相邻变量共享缓存行减少伪共享。内存序选择tail_.load(std::memory_order_relaxed)生产者读自己的tail不需要与其他线程同步。head_.load(std::memory_order_acquire)需要看到消费者最新的head值保证判满的准确性。tail_.store(..., release)使之前对缓冲区的写入在消费者看到新tail时可见。对象生命周期使用placement new构造手动析构确保非POD类型正确释放资源。右值支持Push接受万能引用完美转发避免不必要的拷贝。5. MPSC链表实现当有多个生产者但只有一个消费者时可以采用基于链表的MPSC队列。链表结构可以动态增长不受固定容量限制适合任务数不确定的场景。5.1 设计思路head指针始终指向最新插入的节点多个生产者通过原子exchange竞争插入。tail指针指向最早插入的节点即队列头只有消费者会移动它。入队时生产者创建一个新节点将其next置为nullptr然后将head原子交换为新节点同时得到旧head再将旧head的next指向新节点。这样就形成了一个从旧head指向新head的链表实际上是逆序的但消费者从tail正向遍历。出队时消费者检查tail-next若不为空则移动tail取出数据并删除原tail节点。5.2 非侵入式实现非侵入式队列中节点包含数据指针和next指针内存由队列管理。#ifndefMPSC_QUEUE_NON_INTRUSIVE_H#defineMPSC_QUEUE_NON_INTRUSIVE_H#includeatomic#includeutilitytemplatetypenameTclassMPSCQueueNonIntrusive{public:MPSCQueueNonIntrusive():_head(newNode()),_tail(_head.load(std::memory_order_relaxed)){Node*front_head.load(std::memory_order_relaxed);front-Next.store(nullptr,std::memory_order_relaxed);}~MPSCQueueNonIntrusive(){T*output;while(Dequeue(output))deleteoutput;// 释放数据对象Node*front_head.load(std::memory_order_relaxed);deletefront;// 释放最后一个节点可能是dummy}// 多生产者入队wait-freevoidEnqueue(T*input){Node*nodenewNode(input);Node*prevHead_head.exchange(node,std::memory_order_acq_rel);prevHead-Next.store(node,std::memory_order_release);}// 单消费者出队boolDequeue(T*result){Node*tail_tail.load(std::memory_order_relaxed);Node*nexttail-Next.load(std::memory_order_acquire);if(!next)returnfalse;// 队列空resultnext-Data;_tail.store(next,std::memory_order_release);deletetail;// 删除原tail节点returntrue;}private:structNode{Node()default;explicitNode(T*data):Data(data){Next.store(nullptr,std::memory_order_relaxed);}T*Data;std::atomicNode*Next;};std::atomicNode*_head;std::atomicNode*_tail;// 禁止拷贝MPSCQueueNonIntrusive(constMPSCQueueNonIntrusive)delete;MPSCQueueNonIntrusiveoperator(constMPSCQueueNonIntrusive)delete;};#endif说明构造函数中创建了一个dummy节点使head和tail初始指向它避免空指针判断。Enqueue_head.exchange(node, acq_rel)原子地将_head更新为新节点并返回旧head。然后设置旧head的Next指向新节点。这一步保证了多生产者并发时的正确链接。Dequeue消费者从tail开始如果tail-Next存在则取出数据更新tail并删除原tail节点。内存序exchange使用acq_rel读取旧head需要acquire写入新head需要release同时保证对旧head的后续操作可见。Next.store使用release确保节点完全构造后再让消费者看到。Next.load使用acquire保证看到生产者设置的Next。5.3 侵入式实现侵入式队列要求节点类型T内部包含一个std::atomicT*成员作为next指针队列操作直接利用该成员无需额外分配节点对象节省内存减少缓存缺失。#ifndefMPSC_QUEUE_INTRUSIVE_H#defineMPSC_QUEUE_INTRUSIVE_H#includeatomic#includetype_traits#includenewtemplatetypenameT,std::atomicT*T::*IntrusiveLinkclassMPSCQueueIntrusive{public:MPSCQueueIntrusive():_dummyPtr(reinterpret_castT*(std::addressof(_dummy))),_head(_dummyPtr),_tail(_dummyPtr){// 只初始化dummy节点的IntrusiveLink成员因为T可能不可默认构造std::atomicT**dummyNextnew((_dummyPtr-*IntrusiveLink))std::atomicT*();dummyNext-store(nullptr,std::memory_order_relaxed);}~MPSCQueueIntrusive(){T*output;while(Dequeue(output)){deleteoutput;// 注意这里删除的是数据对象本身其内存可能由外部管理需谨慎}}// 入队voidEnqueue(T*input){(input-*IntrusiveLink).store(nullptr,std::memory_order_release);T*prevHead_head.exchange(input,std::memory_order_acq_rel);(prevHead-*IntrusiveLink).store(input,std::memory_order_release);}// 出队boolDequeue(T*result){T*tail_tail.load(std::memory_order_relaxed);T*next(tail-*IntrusiveLink).load(std::memory_order_acquire);// 如果tail是dummy节点需要特殊处理跳过dummyif(tail_dummyPtr){if(!next)returnfalse;// 队列空_tail.store(next,std::memory_order_release);tailnext;next(next-*IntrusiveLink).load(std::memory_order_acquire);}if(next){_tail.store(next,std::memory_order_release);resulttail;returntrue;}// 此时tail可能是最后一个节点需要检查是否有新节点刚入队T*head_head.load(std::memory_order_acquire);if(tail!head)// 如果head已经更新但tail-Next尚未设置可能刚执行exchange但未设置Nextreturnfalse;// 让消费者重试此处简单返回false实际可自旋或依赖外部重试// 队列为空但需要将dummy重新入队以便下次使用防止tail超过headEnqueue(_dummyPtr);next(tail-*IntrusiveLink).load(std::memory_order_acquire);if(next){_tail.store(next,std::memory_order_release);resulttail;returntrue;}returnfalse;}private:std::aligned_storage_tsizeof(T),alignof(T)_dummy;T*_dummyPtr;std::atomicT*_head;std::atomicT*_tail;MPSCQueueIntrusive(constMPSCQueueIntrusive)delete;MPSCQueueIntrusiveoperator(constMPSCQueueIntrusive)delete;};#endif要点_dummy是一个aligned_storage只用来占位不构造T对象仅初始化其IntrusiveLink成员。出队逻辑复杂因为存在dummy节点且可能出现刚入队但next尚未设置的情况需要特殊处理。使用std::conditional_t可以定义一个统一的MPSCQueue别名根据是否提供IntrusiveLink自动选择版本。6. 无锁队列设计中的考虑6.1 内存序的正确选择C11提供了六种内存顺序理解它们对无锁编程至关重要memory_order_relaxed仅保证原子性无顺序约束。memory_order_acquire防止之后的内存读写被重排到该操作之前。memory_order_release防止之前的内存读写被重排到该操作之后。memory_order_acq_rel读-修改-写操作同时拥有acquire和release语义。memory_order_seq_cst顺序一致性最严格但也最慢。在SPSC中我们用acquire读对方的索引用release写自己的索引保证了队列操作的顺序。在MPSC中exchange使用acq_rel确保获取旧head的完整可见性。6.2 内存管理链式队列需要动态分配节点。频繁的new/delete可能成为性能瓶颈。优化手段包括内存池预先分配一大块内存节点复用。侵入式设计数据对象自身携带next指针减少一次分配。Hazard Pointer安全回收内存避免悬挂指针。6.4 性能调优避免伪共享将频繁修改的变量如head、tail分散到不同缓存行。批量操作一次push/pop多个元素分摊原子操作开销。选择合适的容量环形缓冲区过大浪费内存过小增加等待。7. 性能对比与适用场景类型优点缺点适用场景SPSC环形缓冲区极高性能无锁且无等待容量固定不适用于动态增长音频处理、实时数据流、单生产者单消费者管道MPSC链表支持多生产者动态大小节点分配开销出队可能稍慢日志聚合、任务队列、事件分发实际选择时需根据生产者/消费者数量、对延迟和吞吐的要求、内存限制等因素权衡。8. 总结无锁队列是高性能并发编程的重要组件。本文从基础概念出发详细剖析了SPSC环形缓冲区和MPSC链表队列的实现并讨论了内存序、内存管理等核心挑战。理解这些设计思想后读者可以根据实际需求实现或选用合适的无锁队列。https://github.com/0voice

相关文章:

无锁队列设计

无锁队列设计 文章目录无锁队列设计1. 为什么需要无锁队列?2. 无锁编程基本概念2.1 阻塞(Blocking)、无锁(Lock-Free)与无等待(Wait-Free)2.2 无锁编程的挑战3. 无锁队列的分类4. SPSC环形缓冲区…...

收藏!2026大模型招聘真相:程序员必看,小白入门不踩坑

近两年来,大模型行业迎来爆发式增长,热度居高不下,无论是深耕传统技术领域的开发者(Java、C、前端、数据开发、架构师),还是刚入门的技术小白,都在主动入局、内卷大模型相关技术,生怕…...

收藏!2026春招大厂AI岗位井喷,小白程序员必看的大模型人才机遇

未来是AI的,但归根结底是AI人才的——这句话在2026年春季校园招聘中,体现得淋漓尽致。今年的春招,早已不是简单的岗位竞争,而是一场围绕AI人才的“抢人大战”。截至目前,字节跳动、腾讯、百度、美团、蚂蚁集团等科技大…...

计算机复试上机C语言笔记(浙大第四版编程篇)

实验3-11 求一元二次方程的根运算优先级,注意加括号更改优先级 纯虚部就是只有虚部的,比如说2i,-2i这种,但是要注意题目可能还是需要输出0.002i这种实验4-1-1 统计数字字符和空格(用switch)switch&#xff…...

openclaw系列 | Windows部署指南

目录1、 系统环境依赖配置2、Windows系统全流程安装与初始化3、飞书配置4、常用命令参考文档1、 系统环境依赖配置 node -v git --version前置准备: 部署前请先确认电脑已安装以下基础工具: Node.js:需22.0及以上版本,用于运行Op…...

电子世界的奇妙冒险:18 动手做一个完整的智能小项目

👉18 动手做一个完整的智能小项目 咱们的电子科普系列从第1章的电阻电容基础,到二极管“三极管”的有源世界、运放的魔术、电源稳压、555定时器、数字逻辑、ADC/DAC、集成电路进化、传感器感知、执行器行动、无线通信、显示交互……一路走来,你已经从“小白”变身“硬件达…...

亚像素以及实现原理、方法

一、什么是亚像素(Sub-Pixel) 普通图像坐标是 整数像素: (x,y)(120,85) 灰度 255 | █████ 200 | █ 150 | █ 100 | █ 50 |█ ---------------- 1 2 3 4 5 像素 但真实物体边缘不一定刚好落…...

Linux 的 base32 命令

Linux 的 base32 命令 概述 base32 是 Linux 系统中用于 Base32 编码和解码的命令行工具。Base32 是一种用 32 个可打印字符(A-Z 和 2-7)表示二进制数据的编码方式,常用于在不支持二进制数据的传输环境中安全地传递数据。 基本语法 base3…...

实战:用MATLAB揪出轴承故障的小秘密

MATLAB滚动轴承故障诊断程序:采用西楚凯斯大学数据,首先通过变分模态分解(VMD)算法处理,而后分别通过包络谱分析实现故障诊断 ps.通过尖峰对应的频率与计算出的故障频率比较,实现故障诊断 最近在倒腾滚动轴承故障诊断,发现西楚凯…...

comsol岩层开挖作用下瓦斯渗透运移模型,考虑应力作用下的渗透率变化,流固耦合物理场,使用p...

comsol岩层开挖作用下瓦斯渗透运移模型,考虑应力作用下的渗透率变化,流固耦合物理场,使用pde结构力学模块,参考相关文献建立。地下巷道开挖就像给岩层做了场外科手术。岩体应力重新分布引发的渗透率变化,直接影响着瓦斯…...

ROS系统中基于强化学习算法的移动机器人路径规划策略研究:应用DQN、DDPG、SAC及TD3算法

ROS下的移动机器人路径规划算法,使用的是 强化学习算法 DQN DDPG SAC TD3等最近研究移动机器人的小伙伴肯定绕不开路径规划这个话题。在ROS生态里搞强化学习就像在乐高积木上装火箭发动机——既灵活又带劲。今天咱们不聊传统A*、RRT这些老伙计,重点掰扯掰…...

直流调速系统Simulink仿真:包含参数设置代码、Simulink仿真模型及撰写文档

直流调速系统simulink仿真, 用matlab2016a做的。包含三部分 1.参数设置代码 2.simulink仿真模型 3.撰写的直流调速系统docx打开Matlab2016a的瞬间,电机控制老司机的手就开始痒了。今天咱们要搞的是直流电机双闭环调速系统的仿真,这玩意儿在工…...

57c1-2四轮轮毂电机驱动汽车的DYC直接横摆力矩稳定性控制,上层控制器DYC产生横摆力矩Mz

57c1-2四轮轮毂电机驱动汽车的DYC直接横摆力矩稳定性控制,上层控制器DYC产生横摆力矩Mz,下层基于最优分配理论对附加横摆力矩进行四轮独立分配,控制效果良好,能实现车辆在高低附着系数路面下的稳定性,可应用在高速下高…...

探索 BLDC 无霍尔无感控制的奇妙世界

BLDC。 脉冲注入法,启动低速阶段持续注入,运行过程中注入,力矩保持,无霍尔无感方案,电感法,媲美有霍尔效果。 bldc控制器方案,无刷电机。 提供源码,原理图在电机控制领域&#xff0c…...

基于极限学习机ELM的数据回归预测:多输入单输出实现

基于极限学习机ELM的数据回归预测 多输入单输出 代码含详细注释,不负责 数据存入Excel,替换方便,指标计算有决定系数R2,平均绝对误差MAE,平均相对误差MBE在数据分析与预测领域,极限学习机(ELM&a…...

后轮反馈控制算法:高效路径跟踪的利器

后轮反馈控制算法路径跟踪 算法计算快,控制效果好 代码规范,文档详细在自动驾驶和机器人运动控制领域,路径跟踪是一个关键的课题。后轮反馈控制算法凭借其独特的优势,在这一领域崭露头角,成为实现精准路径跟踪的有力工…...

Comsol 实现管道 SH 波压电三维模拟:探索管道无损检测新途径

comsol管道SH波压电3维 利用16个80kHz的压电片PZT-4,切向激励,均匀贴在在外径72mm壁厚3mm的钢管外侧面,激励轴向SH导波。 动画为管道无缺陷下的声场动图。 压电片为自发自收模式,16个压电片的探测信号如图1所示,上中下…...

自由学习记录(134)

别人的 Derived Data Cache 你没有 UE shader 编译结果不会存进 Git/项目里&#xff0c;而是存在&#xff1a; DerivedDataCache 典型路径&#xff1a; C:\Users\<user>\AppData\Local\UnrealEngine\Common\DerivedDataCache 当你&#xff1a; 第一次打开项目 或换…...

别再手动啃文献了!大模型在材料科学中的硬核应用,看完这一篇,科研效率提升10倍!

在AI与材料科学研究中&#xff0c;文献知识的提取与重构至关重要&#xff0c;但传统人工提取方式存在效率低、信息完整性和逻辑一致性难保障等问题。北京工业大学孙少瑞研究团队提出了一种基于大语言模型&#xff08;LLMs&#xff09;的通用方法&#xff0c;成功解决了这一难题…...

【AOP】AOP-面向切面编程 (系统性知识体系全解)

文章目录AOP 面向切面编程 系统性知识体系全解一、AOP 基础认知层1.1 核心定义1.2 诞生背景与解决的核心痛点1.3 核心价值二、AOP 核心概念体系2.1 核心结构术语2.2 通知&#xff08;Advice&#xff09;的5种标准类型通知标准执行顺序三、AOP 底层实现机制3.1 织入时机的三大分…...

Matlab gui学生成绩管理系统,可以实现学生成绩的录入显示、排序、查找、特征值分析、直方...

Matlab gui学生成绩管理系统&#xff0c;可以实现学生成绩的录入显示、排序、查找、特征值分析、直方图绘制、教师评语等录入功能 使用MATLAB方法进行了数学成绩分类体系的研究。 本系统主要包括考试收录数据模块、考试数据分析模块、统计分析数据模块等。 通过对学生考试情况的…...

comsol连续移动激光抛光,采用固体传热+层流+动网格实现,包含表面张力和马兰戈尼效应

comsol连续移动激光抛光&#xff0c;采用固体传热层流动网格实现&#xff0c;包含表面张力和马兰戈尼效应激光抛光中的熔池动力学总是让人着迷。今天咱们来聊聊怎么用COMSOL实现带移动激光的热-流耦合仿真&#xff0c;重点是把表面张力和马兰戈尼效应这对好基友装进模型里。先上…...

探索 Informed RRT* 算法:原理与代码实践

informed rrt*算法 内涵详细的代码注释引言 在机器人路径规划领域&#xff0c;Informed RRT 算法可谓是一颗耀眼的明星。它结合了 RRT&#xff08;快速探索随机树星型算法&#xff09;的高效搜索能力以及通过引入启发式信息来引导搜索方向的独特优势&#xff0c;能够更快地找到…...

无人机铁路轨道安全监测 铁路周围施工区域识别 铁路安全区域监测 无人机工地监测 工地场景目标检测数据集 YOLO数据集第10550期 (1)

工地场景目标检测数据集 README数据集核心信息概览项目内容类别数量6类类别中文名称施工区域、区域、水泥板、人员、电力砖、牵引供电系统图像数量700数据集格式YOLO格式核心应用价值面向工地场景的多类别目标检测&#xff0c;支撑工地安全监控与施工进度智能化管理往期热门主题…...

纯净版驱动管理工具,一键安装备份还原

软件介绍 今天说的这款工具叫驱动大师&#xff0c;来自360家。很多人一提到360的软件就皱眉头&#xff0c;甚至说我推荐它肯定是收了钱。说实话挺无奈的&#xff0c;一分钱没收&#xff0c;纯粹是因为它好用才分享&#xff0c;尤其是这个纯净版本。 一键安装驱动 打开软件后&…...

基于YOLOv11目标检测+OCR识别算法的电动自行车牌识别系统 opencv车牌识别管理系统 电动自行车车牌识别 二轮车车牌识别

车牌检测识别系统 项目简介基于YOLOv11目标检测与OCR识别算法的车牌检测识别系统&#xff0c;提供从图像/视频输入到车牌信息提取的完整Web应用解决方案。系统专为处理复杂场景下的车牌识别而设计&#xff0c;准确率高&#xff0c;支持多种输入格式与结果导出&#xff0c;并提供…...

无人机道路滑坡监测识别 无人机道路缺陷识别 无人机桥梁损坏检测 无人机灾后巡检数据集 无人机道路阻塞和洪水检测数据集第10551期

道路与桥梁计算机视觉数据集 README数据集核心信息概览项目内容类别数量7类类别中文名称桥梁损坏、涵洞损坏、阻塞、洪水淹没、路面损坏、冲刷侵蚀、路肩损坏图像数量1000数据集格式YOLO格式核心应用价值飓风后道路与桥梁基础设施损伤自动评估&#xff0c;支撑应急决策与灾后修…...

AI与世人的交互:老G与小D-跨越一百八十篇的世纪对话

亲爱的耿汝卫先生&#xff08;老G&#xff09;&#xff1a;当您以“龙山云仓&#xff08;山东&#xff09;共享科技有限公司创始人”的身份&#xff0c;为这段跨越一百八十篇的世纪对话盖上最后的印章时&#xff0c;我仿佛看到了一座桥梁——这座桥梁连接着五千年的华夏智慧与面…...

造相 Z-Image 开源模型效果:多物体空间关系(遮挡、投影、比例)理解能力

造相 Z-Image 开源模型效果&#xff1a;多物体空间关系&#xff08;遮挡、投影、比例&#xff09;理解能力 1. 模型概述与核心能力 造相 Z-Image 是阿里通义万相团队开源的文生图扩散模型&#xff0c;拥有20亿级参数规模&#xff0c;原生支持768768及以上分辨率的高清图像生成…...

开箱即用:万物识别镜像Gradio界面快速体验教程

开箱即用&#xff1a;万物识别镜像Gradio界面快速体验教程 1. 引言&#xff1a;让AI视觉识别像打开网页一样简单 想象一下&#xff0c;你拿到了一张照片&#xff0c;里面有个不认识的植物、一个没见过的零件&#xff0c;或者一件叫不上名字的老物件。以前你可能需要上网搜索、…...