Cell和RefCell
Cell和RefCell
- Cell
- RefCell
- RefCell在运行时记录借用
- 结合Rc和RefCell来拥有多个可变数据所有者
- 引用循环与内存泄漏
- 制造引用循环
- 避免引用循环:将Rc变为Weak
- 创建树形数据结构:带子节点的Node
- 增加从子到父的引用
- 可视化strong_count 和 weak_count 的改变
Rust 提供了 Cell 和 RefCell 用于内部可变性,简而言之,可以在拥有不可变引用的同时修改目标数据,对于正常的代码实现来说,这个是不可能做到的(要么一个可变借用,要么多个不可变借用)。
内部可变性的实现是因为 Rust 使用了 unsafe 来做到这一点,但是对于使用者来说,这些都是透明的,因为这些不安全代码都被封装到了安全的 API 中
Cell
Cell 和 RefCell 在功能上没有区别,区别在于 Cell< T > 适用于 T 实现 Copy 的情况:
use std::cell::Cell;
fn main() {let c = Cell::new("asdf");let one = c.get();c.set("qwer");let two = c.get();println!("{},{}", one, two);asdf,qwer
}
以上代码展示了 Cell 的基本用法,有几点值得注意:
- “asdf” 是 &str 类型,它实现了 Copy 特征
- c.get 用来取值,c.set 用来设置新值
取到值保存在 one 变量后,还能同时进行修改,这个违背了 Rust 的借用规则,但是由于 Cell 的存在,我们很优雅地做到了这一点,但是如果你尝试在 Cell 中存放String:
let c = Cell::new(String::from("asdf"));
编译器会立刻报错,因为 String 没有实现 Copy 特征
RefCell
- Rc< T > 允许相同数据有多个所有者;Box< T > 和 RefCell 有单一所有者。
- Box< T > 允许在编译时执行不可变或可变借用检查;Rc< T > 仅允许在编译时执行不可变借用检查;RefCell< T > 允许在运行时执行不可变或可变借用检查。
- 因为 RefCell< T > 允许在运行时执行可变借用检查,所以我们可以在即便 RefCell< T > 自身是不可变的情况下修改其内部的值。
举个例子
pub trait Messenger {fn send(&self, msg: &str);
}struct MockMessenger {sent_messages: Vec<String>,
}impl MockMessenger {fn new() -> MockMessenger {MockMessenger {sent_messages: vec![],}}
}impl Messenger for MockMessenger {fn send(&self, message: &str) {self.sent_messages.push(String::from(message));}
}
这段代码不会编译成功,因为MockMessenger用的是不可变引用,所以它内部的vec也是不可变的,所以不能push。修改trait的签名是一个好的方法,但是如果不能修改呢?
struct MockMessenger {sent_messages: RefCell<Vec<String>>,}impl MockMessenger {fn new() -> MockMessenger {MockMessenger {sent_messages: RefCell::new(vec![]),}}}impl Messenger for MockMessenger {fn send(&self, message: &str) {self.sent_messages.borrow_mut().push(String::from(message));}}
对于 send 方法的实现,第一个参数仍为 self 的不可变借用,这是符合方法定义的。我们调用 self.sent_messages 中 RefCell 的 borrow_mut 方法来获取 RefCell 中值的可变引用,这是一个 vector。接着可以对 vector 的可变引用调用 push 以便记录测试过程中看到的消息。
RefCell在运行时记录借用
当创建不可变和可变引用时,我们分别使用 & 和 &mut 语法。对于 RefCell< T> 来说,则是 borrow 和 borrow_mut 方法,这属于 RefCell< T> 安全 API 的一部分。borrow 方法返回 Ref< T> 类型的智能指针,borrow_mut 方法返回 RefMut< T> 类型的智能指针。这两个类型都实现了 Deref,所以可以当作常规引用对待。
RefCell< T > 记录当前有多少个活动的 Ref< T > 和 RefMut< T > 智能指针。每次调用 borrow,RefCell< T > 将活动的不可变借用计数加一。当 Ref< T > 值离开作用域时,不可变借用计数减一。就像编译时借用规则一样,RefCell< T > 在任何时候只允许有多个不可变借用或一个可变借用。
如果我们尝试违反这些规则,相比引用时的编译时错误,RefCell< T > 的实现会在运行时出现 panic。
pub trait Messenger {fn send(&self, msg: &str);
}pub struct LimitTracker<'a, T: Messenger> {messenger: &'a T,value: usize,max: usize,
}impl<'a, T> LimitTracker<'a, T>
whereT: Messenger,
{pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {LimitTracker {messenger,value: 0,max,}}pub fn set_value(&mut self, value: usize) {self.value = value;let percentage_of_max = self.value as f64 / self.max as f64;if percentage_of_max >= 1.0 {self.messenger.send("Error: You are over your quota!");} else if percentage_of_max >= 0.9 {self.messenger.send("Urgent warning: You've used up over 90% of your quota!");} else if percentage_of_max >= 0.75 {self.messenger.send("Warning: You've used up over 75% of your quota!");}}
}#[cfg(test)]
mod tests {use super::*;use std::cell::RefCell;struct MockMessenger {sent_messages: RefCell<Vec<String>>,}impl MockMessenger {fn new() -> MockMessenger {MockMessenger {sent_messages: RefCell::new(vec![]),}}}impl Messenger for MockMessenger {fn send(&self, message: &str) {let mut one_borrow = self.sent_messages.borrow_mut();let mut two_borrow = self.sent_messages.borrow_mut();one_borrow.push(String::from(message));two_borrow.push(String::from(message));}}#[test]fn it_sends_an_over_75_percent_warning_message() {let mock_messenger = MockMessenger::new();let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);limit_tracker.set_value(80);assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);}
}
fn main(){}
上面这个代码不会出现编译错误,但是cargo test时会panic
结合Rc和RefCell来拥有多个可变数据所有者
回忆一下 Rc< T> 允许对相同数据有多个所有者,不过只能提供数据的不可变访问。如果有一个储存了 RefCell< T> 的 Rc< T> 的话,就可以得到有多个所有者 并且 可以修改的值了!
#[derive(Debug)]
enum List {Cons(Rc<RefCell<i32>>, Rc<List>),Nil,
}use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;fn main() {let value = Rc::new(RefCell::new(5));let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));*value.borrow_mut() += 10;println!("a after = {:?}", a);println!("b after = {:?}", b);println!("c after = {:?}", c);
}
----------------------------------------------
$ cargo runCompiling cons-list v0.1.0 (file:///projects/cons-list)Finished dev [unoptimized + debuginfo] target(s) in 0.63sRunning `target/debug/cons-list`
a after = Cons(RefCell { value: 15 }, Nil)
b after = Cons(RefCell { value: 3 }, Cons(RefCell { value: 15 }, Nil))
c after = Cons(RefCell { value: 4 }, Cons(RefCell { value: 15 }, Nil))
这里创建了一个 Rc<RefCell< i32>> 实例并储存在变量 value 中以便之后直接访问。接着在 a 中用包含 value 的 Cons 成员创建了一个 List。需要克隆 value 以便 a 和 value 都能拥有其内部值 5 的所有权,而不是将所有权从 value 移动到 a 或者让 a 借用 value。
需要克隆value,以便拥有内部值5的所有权,而不是移动所有权或借用。如果转移所有权,value就用不了了。这里的克隆是浅拷贝,仅仅复制了智能指针并增加了引用计数,并没有克隆底层数据。
Rc与Arc实现1vN所有权机制
通过使用 RefCell< T>,我们可以拥有一个表面上不可变的 List,不过可以使用 RefCell< T> 中提供内部可变性的方法来在需要时修改数据。RefCell< T> 的运行时借用规则检查也确实保护我们免于出现数据竞争——有时为了数据结构的灵活性而付出一些性能是值得的。注意 RefCell< T> 不能用于多线程代码!Mutex< T> 是一个线程安全版本的 RefCell< T> 。
引用循环与内存泄漏
Rust 的内存安全性保证使其难以意外地制造永远也不会被清理的内存(被称为 内存泄漏(memory leak)),但并不是不可能。Rust 并不保证完全防止内存泄漏,这意味着内存泄漏在 Rust 中被认为是内存安全的。这一点可以通过 Rc< T> 和 RefCell< T> 看出:创建引用循环的可能性是存在的。这会造成内存泄漏,因为每一项的引用计数永远也到不了 0,持有的数据也就永远不会被释放。
简单来说,就是,变量超出作用域,或者main函数快结束的时候,Rust会丢弃变量,将其引用计数减1,但是只有为0了,才会被回收!!!
制造引用循环
List 定义的另一种变体。现在 Cons 成员的第二个元素是 RefCell<Rc< List >>
这里还增加了一个 tail 方法来方便我们在有 Cons 成员的时候访问其第二项。
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;#[derive(Debug)]
enum List {Cons(i32, RefCell<Rc<List>>),Nil,
}impl List {fn tail(&self) -> Option<&RefCell<Rc<List>>> {match self {Cons(_, item) => Some(item),Nil => None,}}
}fn main() {let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));println!("a initial rc count = {}", Rc::strong_count(&a));println!("a next item = {:?}", a.tail());let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));println!("a rc count after b creation = {}", Rc::strong_count(&a));println!("b initial rc count = {}", Rc::strong_count(&b));println!("b next item = {:?}", b.tail());if let Some(link) = a.tail() {*link.borrow_mut() = Rc::clone(&b);}println!("b rc count after changing a = {}", Rc::strong_count(&b));println!("a rc count after changing a = {}", Rc::strong_count(&a));// Uncomment the next line to see that we have a cycle;// it will overflow the stack// println!("a next item = {:?}", a.tail());
}
--------------------------------------------
$ cargo runCompiling cons-list v0.1.0 (file:///projects/cons-list)Finished dev [unoptimized + debuginfo] target(s) in 0.53sRunning `target/debug/cons-list`
a initial rc count = 1
a next item = Some(RefCell { value: Nil })
a rc count after b creation = 2
b initial rc count = 1
b next item = Some(RefCell { value: Cons(5, RefCell { value: Nil }) })
b rc count after changing a = 2
a rc count after changing a = 2
这里在变量 a 中创建了一个 Rc< List > 实例来存放初值为 5, Nil 的 List 值。接着在变量 b 中创建了存放包含值 10 和指向列表 a 的 List 的另一个 Rc< List > 实例。
最后,修改 a 使其指向 b 而不是 Nil,这就创建了一个循环。为此需要使用 tail 方法获取 a 中 RefCell<Rc< List >> 的引用,并放入变量 link 中。接着使用 RefCell<Rc< List >> 的 borrow_mut 方法将其值从存放 Nil 的 Rc< List > 修改为 b 中的 Rc< List >。
可以看到将列表 a 修改为指向 b 之后, a 和 b 中的 Rc< List > 实例的引用计数都是 2。在 main 的结尾,Rust 丢弃 b,这会使 b Rc< List > 实例的引用计数从 2 减为 1。然而,b Rc< List> 不能被回收,因为其引用计数是 1 而不是 0。接下来 Rust 会丢弃 a 将 a Rc< List > 实例的引用计数从 2 减为 1。这个实例也不能被回收,因为 b Rc< List > 实例依然引用它,所以其引用计数是 1。这些列表的内存将永远保持未被回收的状态。
如果取消最后 println! 的注释并运行程序,Rust 会尝试打印出 a 指向 b 指向 a 这样的循环直到栈溢出。
避免引用循环:将Rc变为Weak
创建树形数据结构:带子节点的Node
我们希望Node能够拥有其子节点,同时也希望能将所有权共享给变量,以便可以直接访问树中的每一个Node,为此Vec的项的类型被定义为Rc< Node >。我们还希望能够修改其他节点的子节点,因此Children中的Vec被放进了RefCell。
创建leaf,值为3,创建branch,值为5,子结点为leaf。
use std::cell::RefCell;
use std::rc::Rc;#[derive(Debug)]
struct Node {value: i32,children: RefCell<Vec<Rc<Node>>>,
}fn main() {let leaf = Rc::new(Node {value: 3,children: RefCell::new(vec![]),});let branch = Rc::new(Node {value: 5,children: RefCell::new(vec![Rc::clone(&leaf)]),});
}这里克隆了 leaf 中的 Rc<Node> 并储存在 branch 中,这意味着 leaf 中的 Node 现在有两个所有者:leaf和branch。
可以通过 branch.children 从 branch 中获得 leaf,不过无法从 leaf 到 branch。
leaf 没有到 branch 的引用且并不知道它们相互关联。我们希望 leaf 知道 branch 是其父节点。稍后我们会这么做。
增加从子到父的引用
为了使子节点知道其父节点,需要在 Node 结构体定义中增加一个 parent 字段。问题是 parent 的类型应该是什么。我们知道其不能包含 Rc< T >,因为这样 leaf.parent 将会指向 branch 而 branch.children 会包含 leaf 的指针,这会形成引用循环,会造成其 strong_count 永远也不会为 0。
现在换一种方式思考这个关系,父节点应该拥有其子节点:如果父节点被丢弃了,其子节点也应该被丢弃。然而子节点不应该拥有其父节点:如果丢弃子节点,其父节点应该依然存在。这正是弱引用的例子!
use std::cell::RefCell;
use std::rc::{Rc, Weak};#[derive(Debug)]
struct Node {value: i32,parent: RefCell<Weak<Node>>,children: RefCell<Vec<Rc<Node>>>,
}fn main() {let leaf = Rc::new(Node {value: 3,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![]),});println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());let branch = Rc::new(Node {value: 5,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![Rc::clone(&leaf)]),});*leaf.parent.borrow_mut() = Rc::downgrade(&branch);println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
}
-----------------------------------------
leaf parent = None
leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) },
children: RefCell { value: [Node { value: 3, parent: RefCell { value: (Weak) },
children: RefCell { value: [] } }] } })
可视化strong_count 和 weak_count 的改变
use std::cell::RefCell;
use std::rc::{Rc, Weak};#[derive(Debug)]
struct Node {value: i32,parent: RefCell<Weak<Node>>,children: RefCell<Vec<Rc<Node>>>,
}fn main() {let leaf = Rc::new(Node {value: 3,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![]),});println!("leaf strong = {}, weak = {}",Rc::strong_count(&leaf),Rc::weak_count(&leaf),);{let branch = Rc::new(Node {value: 5,parent: RefCell::new(Weak::new()),children: RefCell::new(vec![Rc::clone(&leaf)]),});*leaf.parent.borrow_mut() = Rc::downgrade(&branch);println!("branch strong = {}, weak = {}",Rc::strong_count(&branch),Rc::weak_count(&branch),);println!("leaf strong = {}, weak = {}",Rc::strong_count(&leaf),Rc::weak_count(&leaf),);}println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());println!("leaf strong = {}, weak = {}",Rc::strong_count(&leaf),Rc::weak_count(&leaf),);
}
一旦创建了leaf,那么它的强引用计数为1,弱为0。在内部作用域创建了branch并与leaf关联,此时branch中的Rc< Node>强引用计数为1,弱引用计数为1(Rc::downgrade(&branch);)。同时leaf的强引用计数变为2,因为现在 branch 的 branch.children 中储存了 leaf 的 Rc< Node> 的拷贝,不过弱引用计数仍然为 0。
当内部作用域结束时,branch 离开作用域,其Rc< Node> 的强引用计数减少为 0,所以其 Node 被丢弃。来自 leaf.parent 的弱引用计数 1 与 Node 是否被丢弃无关,所以并没有产生任何内存泄漏!。
branch 离开作用域,Rc< Node> 的强引用计数减少为 0,所以其 Node 被丢弃。来自 leaf.parent 的弱引用计数 1 与 Node 是否被丢弃无关,所以并没有产生任何内存泄漏。
parent弱引用,children强引用。
相关文章:

Cell和RefCell
Cell和RefCell CellRefCellRefCell在运行时记录借用结合Rc和RefCell来拥有多个可变数据所有者引用循环与内存泄漏制造引用循环避免引用循环:将Rc变为Weak创建树形数据结构:带子节点的Node增加从子到父的引用可视化strong_count 和 weak_count 的改变 Rus…...
DaoWiki(基于Django)开发笔记 20231113
DaoWiki(基于Django)开发笔记 20231113 开发环境 操作系统 windows11python版本 3.12.0django版本 4.2.7 构建python虚拟环境 python -m venv daowiki启动python虚拟环境 cd daowiki\Scripts .\activate安装Django pip install django4.2.7创建项目…...

照片放大软件 Topaz Gigapixel AI mac中文版简介
Topaz Gigapixel AI mac是一款使用人工智能功能扩展图像的桌面应用程序,同时添加自然细节以获得惊人的效果。使用深度学习技术,A.I.Gigapixel™可以放大图像并填写其他调整大小的产品遗漏的细节,使用A.I.Gigapixel™,您可以裁剪照…...

某手游完整性校验分析
前言 只是普通的单机手游,广告比较多,所以分析处理了下,校验流程蛮有意思的,所以就分享出来了 1.重打包崩溃处理 样本进行了加固,对其dump出dex后重打包出现崩溃 ida分析地址发现为jni函数引起 利用Xposed直接替换…...

【ElasticSearch】学习使用DSL和RestClient编写查询语句
文章目录 DSL和RestClient的学习前言1、DSL查询文档1.1 查询分类1.2 全文检索查询1.21 全文检索概述1.2.2 基本使用 1.3 精确查询1.3.1 term查询1.3.2 range查询 1.4 地理坐标查询1.4.1 geo_bounding_box查询1.4.2 geo_distance查询 1.5 复合查询1.5.1 常见相关性算法1.5.2 算分…...

asp.net外卖网站系统VS开发mysql数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net外卖网站系统 是一套完善的web设计管理系统,系统采用mvc模式(BLLDALENTITY)系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为mysql,使用c#语…...

2.4.0 Milky Way 强势登场!新功能大爆炸,让你High翻全场!
Yo开发达人们,我们有重磅新功能要给你们放送啦! Check it out 数据汇总不再单调,新的聚合函数登场! compact_state_agg #1359gauge_agg #1370first #1395last #1413mode #1440increase #1476delta #1395time_delta #1405rate #14…...

C语言----静态链接库和动态链接库
在前面的文章中讲到可执行程序的生成需要经过预处理,编译,汇编和链接四个步骤,链接阶段是链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。 需要解读一下库文件,我们可以将库文件等价为压缩包文件&…...

PCA(主成分分析)数据降维技术代码详解
引言 随着大数据时代的到来,我们经常会面临处理高维数据的问题。高维数据不仅增加了计算复杂度,还可能引发“维度灾难”。为了解决这一问题,我们需要对数据进行降维处理,即在不损失太多信息的前提下,将数据从高维空间…...

Git版本控制系统之分支与标签(版本)
目录 一、Git分支(Branch) 1.1 分支作用 1.2 四种分支管理策略 1.3 使用案例 1.3.1 指令 1.3.2 结合应用场景使用 二、Git标签(Tag) 2.1 标签作用 2.2 标签规范 2.3 使用案例 2.3.1 指令 2.3.2 使用示例 一、Git分支&…...

JSP运行环境搭建
将安装JSP引擎的计算机称作一个支持JSP的Web服务器。这个服务器负责运行JSP,并将运行结果返回给用户。 JSP的核心内容之一就是编写JSP页面,JSP页面是Web应用程序的重要组成部分之一。一个简单Web应用程序可能只有一个JSP页面,而一个复杂的Web应用程序可能由许多JSP…...
React通过属性 (props) 和状态 (state) 来传递和管理组件的数据
import React, { useState } from react;// 子组件 const ChildComponent (props) > {return (<div><h2>Hello, {props.name}!</h2></div>); }// 父组件 const ParentComponent () > {const [name, setName] useState(John Doe);const handle…...
Web相机和浏览器的二维码扫描方案
Web相机和适用于浏览器的二维码扫描方案 qr-camera 在线体验 | English 功能 支持浏览器扫描二维码支持拍照支持录像功能支持二维码解析和生成 quickstart npm i qr-cameraimport {QRCamera} from qr-camera;function main(){const camera new QRCamera();document.body…...

云端部署ChatGLM-6B
大模型这里更新是挺快的,我参考的视频教程就和我这个稍微有些不一样,这距离教程发布只过去4天而已… 不过基本操作也差不多 AutoDL算力云:https://www.autodl.com/home ChatGLM3:https://github.com/THUDM/ChatGLM3/tree/main Hug…...

设计模式(3)-结构型模式
结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则…...

C/C++调试工具 - gdb详解
C/C调试工具 -gdb详解 1 简介 2 常用的命令 3 使用的条件 4 程序调试 4.1 直接运行程序 4.2 断点调试(在某一行) 4.3 断点调试(在函数入口处打断点) 5 调试core文件 5.1 生成core文件的方法 5.2 调试core文件 1 简介 GDB是Linux下非常好用且强大的调试工具。GD…...

传奇GOM引擎微端连接不上如何解决
Gom传奇引擎的微端连不上的原因可能有很多,比如网络问题、服务器配置问题、版本兼容性问题等。1.检查网络连接:首先要确保你的网络连接稳定。如果遇到网络问题,比如网络延迟过高,可能会导致你无法连接到服务器。建议使用稳定的网络…...
Easymesh介绍
1.什么是Easymesh 什么是Easymesh,这里需要介绍到有3个点,分别是WFA、MAP和Easymesh。 WFA是Wi-Fi 联盟,Wi-Fi 联盟是专门针对 Wi-Fi 主题的标准创建机构,并且制定新标准,在 Wi-Fi 基础上提供可用功能,全球成员超过 800 家(SoC、制造商和 SW 公司) MAP 是 Multi-AP Te…...

图像相似度对比方法
1.哈希方法,其中包括均值哈希、插值哈希、感知哈希方法。计算出图片的哈希值,一般使用汉明 距离计算两个图片间的差距。 2.直方图算法,其中包括灰度直方图算法,RGB直方图算法, 3.灰度图算法:MSE、SSIM、…...

C++ 配合图形库实现画线效果
#include<stdio.h> #include <conio.h> #include<math.h> #include <graphics.h> // 引用图形库头文件 #define N 12 int List[N][N];void draw() {for (int i 0; i < N; i) {int x 200 * cos(2 * 3.14 * i / N);int y 200 * sin(2 * 3.1…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器
从本章节开始,进入到函数有多个参数的情况,前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参,ECX是整型的第一个参数的寄存器,那么多个参数的情况下函数如何传参,下面展开介绍参数为整型时候的几种情…...