C++ 内存序在多线程中的使用
目录
一、内存顺序
二、 指令重排在多线程中的问题
2.1 问题与原因
2.2 解决方案
三、六种内存序
3.1 memory_order_relaxed
3.2 memory_order_consume
3.3 memory_order_acquire
3.4 memory_order_release
3.5 memory_order_acq_rel
3.6 memory_order_seq_cst
一、内存顺序
内存顺序是指在并发编程中, 对内存读写操作的执行顺序. 这个顺序可以被编译器和处理器进行优化, 可能会与代码中的顺序不同, 这被称为指令重排。
如下代码,如果不处理器不能重拍两个加法的指令,则只能一行一行去执行;但是如果可以重拍指令,则可以在不同的处理单元中并行执行这两个加法操作,发挥处理器执行流水线的优势。
int x = 0, y = 1, a = 0, b = 1;
void testMemoryOrder() {
a = b + 2;
x = y + 2; }
二、 指令重排在多线程中的问题
2.1 问题与原因
在多线程中指令重排会引起一些问题,比如如下场景:
std::atomic<bool> ready{false};
std::atomic<int> data{0};void producer() { data.store(100, std::memory_order_relaxed); // 原子性的更新data的值, 但是不保证内存顺序 ready.store(true, std::memory_order_relaxed); // 原子性的更新ready的值, 但是不保证内存顺序
}void consumer() { // 原子性的读取ready的值, 但是不保证内存顺序 while (!ready.load(memory_order_relaxed)) { std::this_thread::yield(); //让出CPU时间片 } // 当ready为true时, 再原子性的读取data的值 std::cout << data.load(memory_order_relaxed); // 4. 消费者线程使用数据
}int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0;
}
我们预期的效果应该是当消费者看到ready为true时, 此时再去读取data的值。但实际的情况是, 消费者看到ready为true后, 读取到的data值可能仍然是0。
一方面可能是指令重排引起的:在producer线程里, data和store是两个不相干的变量, 所以编译器或者处理器可能会将data.store(100, std::memory_order_relaxed);重排到ready.store(true, std::memory_order_relaxed);之后执行, 这样consumer线程就会先读取到ready为true, 但是data仍然是0。
另一方面可能是内存顺序不一致引起的: 即使producer线程中的指令没有被重排, 但CPU的多级缓存会导致consumer线程看到的data值仍然是0。下面这张示意图来说明这个问题和CPU多级缓存的关系。
每个CPU核心都有自己的L1 Cache与L2 Cache。producer线程修改了data和ready的值, 但修改的是L1 Cache中的值,producer线程和consumer线程的L1 Cache并不是共享的,所以consumer线程不一定能及时的看到producer线程修改的值。CPU Cache的同步是件很复杂的事情, 生产者更新了data和ready后,还需要根据MESI协议将值写回内存,并且同步更新其他CPU核心Cache里data和ready的值,这样才能确保每个CPU核心看到的data和ready的值是一致的。而data和ready同步到其他CPU Cache的顺序也是不固定的,可能先同步ready,再同步data, 这样的话consumer线程就会先看到ready为true, 但data还没来得及同步,所以看到的仍然是0。
2.2 解决方案
void producer()
{ data.store(100, std::memory_order_relaxed); // 原子性的更新data的值, 但是不保证内存顺序 ready.store(true, std::memory_order_released); // 保证data的更新操作先于ready的更新操作
}void consumer()
{ // 保证先读取ready的值, 再读取data的值 while (!ready.load(memory_order_acquire)) { std::this_thread::yield(); } // 当ready为true时, 再原子性的读取data的值 std::cout << data.load(memory_order_relaxed);}
-
ready.store(true, std::memory_order_released):一方面限制ready之前的所有操作不得重排到ready之后,以保证先完成data的写操作, 再完成ready的写操作。 另一方面保证先完成data的内存同步, 再完成ready的内存同步,以保证consumer线程看到ready新值的时候,一定也能看到data的新值。
-
ready.load(memory_order_acquire): 限制ready之后的所有操作不得重排到ready之前, 以保证先完成读ready操作,再完成data的读操作;
三、六种内存序
多线程程序中,为了保证程序的一致性和正确性,需要对内存操作的顺序进行控制。因为在现代处理器中,由于缓存一致性、乱序执行等优化,指令可能不会按顺序执行。内存序允许开发者显式地指定不同操作的顺序,以保证数据的一致性。
C++11 引入了 <atomic> 头文件,并定义了几种内存序类型,来控制原子操作的执行顺序,std::atomic提供了以下几个常用接口来实现原子性的读写操作:
// 原子性的写入值
std::atomic<T>::store(T val, memory_order sync = memory_order_seq_cst);
// 原子性的读取值
std::atomic<T>::load(memory_order sync = memory_order_seq_cst);
// 原子性的增加 counter.fetch_add(1)等价于++counter
std::atomic<T>::fetch_add(T val, memory_order sync = memory_order_seq_cst);
// 原子性的减少 counter.fetch_sub(1)等价于--counter
std::atomic<T>::fetch_sub(T val, memory_order sync = memory_order_seq_cst);
// 原子性的按位与 counter.fetch_and(1)等价于counter &= 1
std::atomic<T>::fetch_and(T val, memory_order sync = memory_order_seq_cst);
// 原子性的按位或 counter.fetch_or(1)等价于counter |= 1
std::atomic<T>::fetch_or(T val, memory_order sync = memory_order_seq_cst);
// 原子性的按位异或 counter.fetch_xor(1)等价于counter ^= 1
std::atomic<T>::fetch_xor(T val, memory_order sync = memory_order_seq_cst);
memory_order用于指定内存顺序不同的内存序提供了不同的同步和顺序保证,从最弱到最严格依次如下 :
memory_order_relaxed(松散顺序)
memory_order_consume(消费顺序)
memory_order_acquire(获取顺序)
memory_order_release(释放顺序)
memory_order_acq_rel(获取-释放顺序)
memory_order_seq_cst(顺序一致性)
3.1 memory_order_relaxed
基本概念:最宽松的内存序,它只保证操作的原子性,不涉及任何线程间的同步或顺序保证。这种方式下,编译器和CPU可以任意重排指令,但仍然保证操作是原子的。
应用场景: 当只需要在多线程环境中执行简单的原子操作,而不需要与其他线程同步时,memory_order_relaxed 是最佳选择,典型场景是简单的计数器或统计类操作。
std::atomic<int> counter(0);
//能保证原子性统计最终一致
void increment() {for (int i = 0; i < 100; ++i) {counter.fetch_add(1, std::memory_order_relaxed); // 放松顺序}
}
3.2 memory_order_consume
基本概念:消费顺序,用于确保在同一线程中,依赖于原子操作结果的读操作不会被重排到该原子操作之前。虽然设计上适用于生产者-消费者模型,但由于硬件优化,memory_order_consume 通常等同于 memory_order_acquire。
应用场景:在多线程中,当一个线程生产数据,另一个线程消费数据并依赖这些数据时,可以使用 memory_order_consume。
std::atomic<int> p;void producer() {p.store(100, std::memory_order_release); // 发布数据
}void consumer() {int p = ptr.load(std::memory_order_consume); std::cout << "Consumed: " << p << std::endl;}
3.3 memory_order_acquire
基本概念:获取顺序,确保在当前线程中,会在读操作之后插入一个LoadLoad屏障, 确保屏障之后的所有操作不会重排到屏障之前。这意味着,在线程读取数据后,它可以看到其他线程对共享变量的修改。
使用场景:当你需要在读取数据时,确保前面的操作已经完成。
std::atomic<int> flag(0);
int data = 0;void writer() {data = 100;flag.store(1, std::memory_order_release); // 先改data更新flag
}void reader() {while (flag.load(std::memory_order_acquire) != 1); // 等待flag更新std::cout << "Data: " << data << std::endl; // 保证读取到最新的data值
}
3.4 memory_order_release
基本概念:释放顺序,确保在当前线程中,会在写操作之前插入一个StoreStore屏障, 确保屏障之前的所有操作不会重排到屏障之后。这意味着,其他线程在看到这个原子操作之后,也可以看到该线程之前的所有修改。
使用场景:当你需要在更新共享数据时,确保在更新操作之前的写入已经完成。同上 flag.store(1, std::memory_order_release);保证执行到此处时,前面的data=100已经执行且对其他线程可见。
3.5 memory_order_acq_rel
基本概念:获取-释放顺序,等效于memory_order_acquire和memory_order_release的组合,同时插入一个StoreStore屏障与LoadLoad屏障,确保当前线程中的操作既能看到其他线程的修改,又可以发布自己的修改。这种顺序适用于同时需要同步读写的场景。
应用场景:当一个线程既要读取其他线程的状态,又要写入新的状态时,使用 memory_order_acq_rel
。例如锁的实现。它的作用是确保 线程 B 在读取 x
时,所有之前对 x
的修改(或者其他操作)都已经完成,并且不会被延迟到 x
被读取之后,线程 B 之后的操作(比如打印 x
的值)不会在 x
读取之前执行。
std::atomic<int> x{0};void threadA() {x.fetch_add(1, std::memory_order_acq_rel); // 获取-释放操作
}void threadB() {// 获取操作while (x.load(std::memory_order_acquire) == 0) { //等待交出时间片}std::cout << "Thread B can proceed";
}
3.6 memory_order_seq_cst
基本概念:顺序一致性(Sequentially Consistent),保证所有线程看到的操作顺序是一致的,原子变量默认顺序。
被memory_order_seq_cst标记的写操作,会立马将新值写回内存,而不仅仅只是写到Cache里就结束了;被memory_order_seq_cst标记的读操作,会立马从内存中读取新值,而不是直接从Cache里读取。这样相当于多个线程读写都在一个内存中,也就不存在Cache同步的顺序不一致问题。相比其他的memory_order,memory_order_seq_cst当于禁用了CPU Cache,会带来最大的性能开销了。
使用场景:当需要确保所有线程对全局状态的顺序一致时,使用 memory_order_seq_cst
。它适合那些需要绝对严格的同步场景。
相关文章:
C++ 内存序在多线程中的使用
目录 一、内存顺序 二、 指令重排在多线程中的问题 2.1 问题与原因 2.2 解决方案 三、六种内存序 3.1 memory_order_relaxed 3.2 memory_order_consume 3.3 memory_order_acquire 3.4 memory_order_release 3.5 memory_order_acq_rel 3.6 memory_order_seq_cst 一、…...
【MySQL】表的操作
文章目录 👉表的操作👈创建表查看表修改表删除表 👉表的操作👈 创建表 create tabletable_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;说明:…...
【Flink银行反欺诈系统设计方案】3.欺诈的7种场景和架构方案、核心表设计
【Flink银行反欺诈系统设计方案】3.欺诈的7种场景和架构方案、核心表设计 1. **欺诈场景分类与案例说明**1.1 **大额交易欺诈**1.2 **异地交易欺诈**1.3 **高频交易欺诈**1.4 **异常时间交易欺诈**1.5 **账户行为异常**1.6 **设备指纹异常**1.7 **交易金额突变** 2. **普适性软…...
DeepSeek-R1本机部署(VLLM+OpenWebUI)
本文搭建环境 系统:Ubuntu 22.04.4 LTS Python版本:Python 3.10 显卡:RTX 4090D 一、DeepSeek-R1-14b原始模型和q8量化模型 1.从modelscope下载模型 官方原始模型:https://modelscope.cn/models/deepseek-ai/DeepSeek-R1-Di…...
计算机网络软考
1.物理层 1.两个主机之间发送数据的过程 自上而下的封装数据,自下而上的解封装数据,实现数据的传输 2.数据、信号、码元 码元就是数字通信里用来表示信息的基本信号单元。比如在二进制中,用高电平代表 “1”、低电平代表 “0”,…...
vscode 查看3d
目录 1. vscode-3d-preview obj查看ok 2. vscode-obj-viewer 没找到这个插件: 3. 3D Viewer for Vscode 查看obj失败 1. vscode-3d-preview obj查看ok 可以查看obj 显示过程:开始是绿屏,过了1到2秒,后来就正常看了。 2. vsc…...
HTML第三节
一.初识CSS 1.CSS定义 A.内部样式表 B.外部样式表 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title&g…...
爬虫去重:数据采集时如何进行去重,及去重优化策略
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. 去重的核心思路2. 常见的去重方法2.1 基于集合(Set)的去重2.2 基于布隆过滤器(Bloom Filter)的去重2.3 基于数据库的去重2.4 基于文件存储的去重2.5 基于 Redis 的去重3. 去重的优化策略3.1 URL 规范化3.2 分片去…...
IDEA集成DeepSeek,通过离线安装解决无法安装Proxy AI插件问题
文章目录 引言一、安装Proxy AI1.1 在线安装Proxy AI1.2 离线安装Proxy AI 二、Proxy AI中配置DeepSeek2.1 配置本地部署的DeepSeek(Ollama方式)2.2 通过第三方服务商提供的API进行配置 三、效果测试 引言 许多开发者尝试通过安装Proxy AI等插件将AI能力…...
【电子基础】运算放大器应用笔记(持续更新)
目录 运放应用1: 运放基础知识同相比例运算放大器计算放大倍数 电压比较器 运放应用2:500W调压器同相比例运算放大器计算放大倍数计算平衡电阻 积分电路 运放应用3:逆变电焊机电压跟随器积分电路 加油站1. 为什么比例运算放大电路要加平衡电阻…...
计算机网络核心知识点:信道容量、OSI模型与调制技术详解
目录 一、信道容量与调制技术 奈奎斯特定理(无噪声环境) 核心公式: 参数说明: 应用场景: 香农定理(有噪声环境) 核心公式: 参数说明: 应用场景: 奈奎…...
AI赋能企业协作4-NL2Sql技术路线
1.1 对话即服务的一点思考 在数智化转型的过程中,基于即时通信(IM)的协作平台正悄然成为企业智能化转型的“新基建”。协作平台天然具备高频交互、实时协同和场景化落地的特性,仿佛是为对话式AI量身定制的试验场——员工在熟悉的聊…...
如何用FFmpeg高效拉流(避坑指南)
FFmpeg作为音视频处理领域的“瑞士军刀”,其拉流功能在直播、监控、流媒体分析等场景中应用广泛。本文从实战角度出发,系统梳理FFmpeg拉流的核心工具链、协议适配技巧及高频踩坑点,助你快速掌握流媒体处理核心技能! 一、FFmpeg拉流工具链全解析 核心工具 ffplay:快速验证…...
面试基础--MySQL SQL 优化深度解析
MySQL SQL 优化深度解析:EXPLAIN、索引优化与分库分表实践 引言 在互联网大厂的高并发场景下,数据库的性能优化是至关重要的。MySQL 作为最流行的关系型数据库之一,SQL 查询的性能直接影响了系统的响应时间和吞吐量。本文将深入探讨 MySQL …...
WebRTC简介
WebRTC简介 WebRTC(Web Real-Time Communication)是一种支持浏览器之间进行实时音视频通信和数据传输的开放标准和技术。它由Google发起,现已成为W3C和IETF的标准。WebRTC允许开发者在不依赖第三方插件或软件的情况下,直接在网页…...
清北deepseek8本手册
“清北手册”通常是“清华大学和北京大学推出的DeepSeek手册”的简写。近期,随着AI技术的迅速发展,清北两高校陆续发布多本自家的DeepSeek学习手册,助力普通人学习进阶。 清华大学的DeepSeek手册已推出5册,内容丰富全面࿰…...
前后分离文件上传案例,前端HTML,后端Net6开发的webapi(完整源代码)下载
文件上传功能在项目开发中非常实用,本案例前端用HTML页面的form表单实现,后端用Net6实现。 前后分离文件上传案例,前端HTML,后端Net6(完整源代码) 下载链接https://download.csdn.net/download/luckyext/9…...
6.过拟合处理:确保模型泛化能力的实践指南——大模型开发深度学习理论基础
在深度学习开发中,过拟合是一个常见且具有挑战性的问题。当模型在训练集上表现优秀,但在测试集或新数据上性能大幅下降时,就说明模型“记住”了训练数据中的噪声而非学习到泛化规律。本文将从实际开发角度系统讲解如何应对过拟合,…...
六十天前端强化训练之第一天到第七天——综合案例:响应式个人博客项目
欢迎来到编程星辰海的博客讲解 目录 前言回顾 HTML5与CSS3基础 一、知识讲解 1. 项目架构设计(语义化HTML) 2. 响应式布局系统(Flex Grid) 3. 样式优先级与组件化设计 4. 完整响应式工作流 二、核心代码示例 完整HTML结…...
java数据结构_再谈String_10
目录 字符串常量池 1. 创建对象的思考 2. 字符串常量池(StringTable) 3. 再谈String对象创建 字符串常量池 1. 创建对象的思考 下面两种创建String对象的方式相同吗? public static void main(String[] args) {String s1 "hello&…...
MCP:重塑AI与数据交互的新标准
MCP:重塑AI与数据交互的新标准 前言 在人工智能领域,大型语言模型(LLM)的应用日益广泛,但其与外部数据源和工具的集成却一直面临复杂性和碎片化的挑战。 Anthropic提出的MCP(Model Context Protocol&…...
Cursor+Claude3.7实现从原型到app开发
最近在X上看到了一些人在用Claude 3.7 Sonnet生成 app原型图的尝试,受到启发,发现这么先生成不同界面的原型图再让Cursor基于原型图开发app会是很好的尝试。尤其是,你也可以不两步直接生成,而是在过程中更可视化地思考你要生产的原…...
洛谷P1334
题目如下 思路: 每次选择最短的两块木板进行合并,直到只剩下一块木板。使用最小堆(优先队列)来实现这一过程。使用最小堆: 将所有木板的长度放入最小堆(优先队列) 每次从堆中取出两块最短的木…...
使用wifi连接手机adb进行调试|不使用数据线adb调试手机|找应用错误日志和操作日志
手机在开发者选项里要开启无线调试 在手机设置中查看WiFi的IP地址 设置 -> WLAN -> 已连接的WiFi -> IP地址 使用手机的IP地址连接 adb connect 192.168.1.12:xxxxx 检查连接状态 adb devices 断开特定设备 adb disconnect 192.168.x.x:xxxxx 断开所有设备 …...
大语言模型中温度参数(Temperature)的核心原理
大语言模型中温度参数(Temperature)的核心原理是通过调整模型输出的概率分布,控制生成结果的随机性和多样性。以下是其原理的详细说明: 一、定义与核心作用 温度参数是生成式模型(如GPT系列)中的一个超参数…...
【AIGC】通义万相 2.1 与蓝耘智算:共绘 AIGC 未来绚丽蓝图
一、引言 在人工智能技术迅猛发展的今天,AIGC(生成式人工智能内容生成)领域正以惊人的速度改变着我们的生活和工作方式。从艺术创作到影视制作,从广告设计到智能客服,AIGC 技术的应用越来越广泛。通义万相 2.1 作为一…...
在Ubuntu上搭建Samba服务,实现与windows之间的文件共享
1.安装samba 首先切换为root账户,就是带#符号的表示当前登录的是root超级用户; su - 如果忘记密码,就输入以下命令修改密码 sudo passwd root 再切换为超级用户 然后进行更新软件列表 sudo apt update sudo apt install samba安装 whe…...
Labview培训案例3: 输出正弦波并采集显示
本案例介绍如何从板卡(USB6008)的模拟量输出端口输出一个正弦波,然后模拟量输入模块进行采样,然后显示到vi画面的‘波形图’中。 详细代码在:Labview课程3:正弦波输出&采集数据&显示资源-CSDN文库 …...
使用 Deepseek + kimi 快速生成PPT
前言 最近看到好多文章和视频都在说,使用 Deepseek 和 kimi 能快速生成精美的 ppt,毕竟那都是别人说的,只有自己尝试一次才知道结果。 具体操作 第一步:访问 deepseek 我们访问 deepseek ,把我们想要输入的内容告诉…...
图解MOE大模型的7个核心问题并探讨DeepSeekMoE的专家机制创新
原文地址:https://newsletter.maartengrootendorst.com/p/a-visual-guide-to-mixture-of-experts #mermaid-svg-FU7YUSIfuXO6EVHa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-FU7YUSIfuXO6EVHa .error-icon{fill…...
青训营:简易分布式爬虫
一、项目介绍 该项目是一个简易分布式爬虫系统,以分布式思想为基础,通过多节点协作的方式,将大规模的网页抓取任务分解,从而高效、快速地获取网络数据 。 项目地址:https://github.com/yanchengsi/distributed_crawle…...
Scala(Array,List,Set,Map,Tuple,字符串 使用的简单介绍)
目录 Array 不可变数组 ArrayBuffer可变数组 List 不可变列表 ListBuffer 可变列表 Set 集合(可变不可变) Map映射(可变不可变)(键值对) Tuple 元组 字符串 Array 不可变数组 // Array 数组// scala 中的数组下标是()// scala 中的数组是值…...
fmql之Linux WDT
正点原子第52章。 基础知识 正点原子教程 fmql-dts 代码 APP代码(不需要编写驱动代码) static int dw_wdt_drv_probe(struct platform_device *pdev) {struct device *dev &pdev->dev;struct watchdog_device *wdd;struct dw_wdt *dw_wdt; …...
IntelliJ IDEA集成MarsCode AI
IntelliJ IDEA集成MarsCode AI IDEA中安装插件 安装完毕之后登录自己的账号 点击链接,注册账号 https://www.marscode.cn/events/s/i5DRGqqo/ 可以选择不同的模型...
python-leetcode-打家劫舍 III
337. 打家劫舍 III - 力扣(LeetCode) 这个问题可以通过动态规划解决。可以通过递归的方式来解决每个房子的最大偷窃金额,递归过程中,我们会记录每个房子是否偷或不偷时能够获得的最大金额。 思路: 对于每个房子,我们有两种选择: 偷这个房子,那么它的直接相邻(父亲和孩…...
数据结构——队列
1. 概念与结构 队列(Queue)是一种先进先出(FIFO, First In First Out)的数据结构,即最先被插入队列的数据会最先被删除。队列广泛应用于计算机科学中,特别是在任务调度、缓冲区管理、网络数据传输等领域。…...
GaussianCity:实时生成城市级数字孪生基底的技术突破
在空间智能领域,如何高效、大规模地生成高质量的3D城市模型一直是一个重大挑战。传统方法如NeRF和3D高斯溅射技术(3D-GS)在效率和规模上存在显著瓶颈。GaussianCity通过创新性的技术方案,成功突破了这些限制,为城市级数字孪生的构建提供了全新路径。 一、核心创新:突破传…...
【AGI】智谱开源2025:一场AI技术民主化的革命正在到来
智谱开源2025:一场AI技术民主化的革命正在到来 引言:开源,一场技术平权的革命一、CogView4:中文AI生成的里程碑1. 破解汉字生成的“AI魔咒”2. 开源协议与生态赋能 二、AutoGLM:人机交互的范式跃迁1. 自然语言驱动的跨…...
【算法学习之路】5.贪心算法
贪心算法 前言一.什么是贪心算法二.例题1.合并果子2.跳跳!3. 老鼠和奶酪 前言 我会将一些常用的算法以及对应的题单给写完,形成一套完整的算法体系,以及大量的各个难度的题目,目前算法也写了几篇,题单正在更新…...
C++11中的右值引用和完美转发
C11中的右值引用和完美转发 右值引用 右值引用是 C11 引入的一种新的引用类型,用 && 表示。它主要用于区分左值和右值,并且可以实现移动语义,避免不必要的深拷贝,提高程序的性能。左值通常是可以取地址的表达式…...
Leetcode 1477. 找两个和为目标值且不重叠的子数组 前缀和+DP
原题链接: Leetcode 1477. 找两个和为目标值且不重叠的子数组 class Solution { public:int minSumOfLengths(vector<int>& arr, int target) {int narr.size();int sum0;int maxnINT_MAX;vector<int> dp(n,maxn);//dp[i]表示以索引i之前的满足要求…...
koa-session设置Cookie后获取不到
在谷歌浏览器中请求获取不到cookie问题之一(谷歌安全策略) 场景 前端使用 axios 请求,项目地址:http://192.168.8.1:5173 import axios from axiosconst request axios.create({baseURL: http://127.0.0.1:3001/,timeout: 60000,…...
Linux三种网络方式
前言 发现运维啥都得会,这周就遇到了网络问题自己无法解决,因此痛定思痛学一下。 参考文献 你管这破玩意叫网络? 桥接模式、NAT模式、仅主机模式,原来是这样工作的 交换机 构成局域网,实现所有设备之间的通信。 …...
android_viewtracker 原理
一、说明 我们业务中大部分场景是用 RecyclerView 实现的列表,而 View 的曝光通常是直接写在 adapter 的 onBindViewHolder 中,这样就会导致 item 还没显示出来的时候就会触发曝光。最近业务提出需要实现根据 View 显示在屏幕上面积大于 80% 才算曝光。…...
Object.defineProperty()
**Object.defineProperty()** 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 plain const object1 {}; Object.defineProperty(object1, ‘property1’, { value: 42, writable: false }); object1.property1 77…...
大模型+知识图谱:重塑企业制度标准管理
在数字化转型的浪潮中,制度标准管理领域正迎来一场革命性的变革。借助大模型和知识图谱等前沿人工智能技术,制度标准管理不再仅仅是简单的文档存储和检索,而是演变为一个智能化、高效化、精准化的管理体系。 1.关键技术 我们的制度标准管理…...
ubuntu20系统下conda虚拟环境下安装文件存储位置
在 Conda 虚拟环境中执行 pip install 安装软件后,安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤: 1. 确认 Conda 虚拟环境的安装路径 查看所有环境: conda info --env…...
深度学习编译器(整理某survey)
一、深度学习框架 TensorFlow PyTorch MXNet ONNX:定义了一个统一的表示,DL models的格式方便不同框架之间的转换模型 二、深度学习硬件 通用硬件(CPU、GPU):通过硬件和软件优化支持深度学习工作负载 GPU:通过多核架构实现高…...
Python学习第八天
查看函数参数 操作之前给大家讲一个小技巧:如何查看函数的参数(因为python的底层源码是C语言并且不是开放的,也一直困扰着刚学习的我,这个参数叫什么名之类的看doc又总是需要翻译挺麻烦的)。 比如我们下面要说到的op…...
SpringBoot为什么默认使用CGLIB?
大家好,我是锋哥。今天分享关于【SpringBoot为什么默认使用CGLIB?】面试题。希望对大家有帮助; SpringBoot为什么默认使用CGLIB? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 默认使用 CGLIB(Code Generation Li…...