为什么 Chromium 正在远离锁?——从一个转账例子理解锁最大的缺陷

浏览器端AI无障碍助手:全本地化语音交互实现原理 语音交互是Web无障碍的核心入口,其本质是将用户语音指令转化为精准DOM操作的技术闭环。传统方案依赖云端处理,导致延迟高、隐私弱、响应不自然;而现代浏览器端AI通过WebGPU加速、WebAssembly推理与IndexedDB模型缓存,实现了VAD检测、Whisper转写、Gemma意图解析的全链路本地化。这种架构不仅保障数据不出设备,更以预加载、双引擎协同和坐标预测等机制,将端到端响应压缩至1.2秒内,显著提升视障、老年及运动障碍用户的操作自然度。本文详解Hey AI Browser-Native Co 阅读详情

引言:锁不是万能药

很多人刚接触并发编程时,都会觉得锁(Mutex)是解决线程安全问题的万能工具。两个线程同时修改一个变量?加把锁。多个函数访问同一个数据结构?加把锁。仿佛只要看到多线程,第一反应就是"上锁"。

然而,当你真正阅读 Chromium、Linux Kernel、Rust 等大型项目源码时,会发现一个有趣的现象:它们都在尽可能减少锁的使用,转而采用 Sequence、Message Passing、Actor Model、Task 等设计。

为什么会这样?

常见的解释是:锁容易死锁,锁的性能差,锁容易写错。这些答案都对,但都没有触及问题的本质。

锁真正的问题在于:它破坏了模块化(Composability)。

这篇文章会从一个简单的转账例子出发,逐步揭示锁的这个根本缺陷,然后介绍 Chromium 是如何通过"避免共享"来从根本上解决这个问题的。


一、锁诞生的理由:解决数据竞争

在批判锁之前,我们首先要承认:锁解决了真实的问题。

假设我们有一个银行账户,初始余额为 100。两个线程同时操作:

cpp

// 线程 A
balance += 100;

// 线程 B
balance -= 50;

我们期望的结果是 100 + 100 - 50 = 150。但在没有同步机制的情况下,CPU 的实际执行顺序可能是这样的:

text

初始余额:100

线程 A (balance += 100)              线程 B (balance -= 50)
─────────────────────────────────────────────────────────
读取 balance → 100
                                      读取 balance → 100
计算 100 + 100 = 200
                                      计算 100 - 50 = 50
写回 balance = 200
                                      写回 balance = 50  ← 覆盖了 A 的结果

最终余额:50(期望 150)

线程 B 的写入覆盖了线程 A 的结果,这就是经典的数据竞争(Race Condition)。

于是 Mutex 出现了:

cpp

std::lock_guard<std::mutex> lock(mutex_);
balance += 100;

任何时刻只有一个线程能进入临界区,数据竞争被消除了。

所以,锁不是坏东西。它在保护简单共享数据时依然是最直接有效的工具。


二、锁的六宗罪

Simon Peyton Jones 在《代码之美》中总结了锁的六个典型问题。在进入核心论点之前,我们先快速回顾一下:

① 锁少了——竞态条件

忘记加锁,或者某些代码路径没有正确加锁。这是最经典的错误,也是最容易出现的。

② 锁多了——性能问题

锁的粒度过大,大量线程排队等待,导致 UI 卡顿、吞吐量下降。Chrome 中有一句铁律:

Never block the UI thread.

UI 线程绝对不能等锁。

③ 锁不匹配——保护关系失控

同一个数据被不同的锁保护,锁和数据之间没有任何强制绑定关系:

cpp

struct Account {
    int money;
};

// 程序员 A 认为 user_lock 保护 money
// 程序员 B 认为 account_lock 保护 money

// 线程 1
lock(user_lock);
account.money += 100;
unlock(user_lock);

// 线程 2
lock(account_lock);
account.money -= 50;
unlock(account_lock);

两把不同的锁保护同一份数据,Race 依然存在。这种"保护关系"只存在于程序员的脑子里,编译器不知道,IDE 不知道,静态分析工具也很难发现。

④ 锁顺序——死锁

cpp

// 线程 A
lock(A);
lock(B);

// 线程 B
lock(B);
lock(A);

两个线程互相等待对方释放锁,经典死锁。大型项目一般会强制规定锁的获取顺序(如 A → B → C),但这种规则只能靠团队纪律维护,没有任何机制能自动保证。

⑤ 条件变量——容易出错

忘记 notify、虚假唤醒、wait 的位置不对……条件变量相关的 Bug 往往难以调试和复现。

⑥ 最根本的问题:锁不能模块化

前面五个问题是"症状",第六个才是"病根"。

这也是本文要重点展开的核心论点。


三、为什么说锁不能模块化?

让我们通过一个仓库搬货的例子来理解。

3.1 两个正确的函数

假设我们有两个仓库 A 和 B,各自有一把锁保护:

cpp

// 从 A 仓库取出 10 箱货
void TakeOut(Inventory& A, int count) {
    lock(A.mutex);
    A.quantity -= count;
    unlock(A.mutex);
}

// 向 B 仓库放入 10 箱货
void PutIn(Inventory& B, int count) {
    lock(B.mutex);
    B.quantity += count;
    unlock(B.mutex);
}

单独来看,这两个函数都是正确的。任何时候调用 TakeOut(A, 10) 或 PutIn(B, 10) 都不会出现问题。

3.2 看似自然的组合

现在老板提了一个新需求:把 10 箱货从 A 仓库搬到 B 仓库。

最自然的想法是什么?

cpp

void Transfer(Inventory& A, Inventory& B, int count) {
    TakeOut(A, count);
    PutIn(B, count);
}

是不是非常自然?这就是函数组合(Composition)的魅力——用简单函数构建复杂功能。

3.3 完全错误

但这段代码是错误的。让我们看看执行过程:

text

初始状态:
  A = 100
  B = 50
  总库存 = 150

Transfer 开始执行:
  第一步:TakeOut(A, 10) 执行完毕
    lock(A)
    A = 90
    unlock(A)  ← 锁已经释放!

  在这一瞬间,另一个线程开始盘点库存:
    Inventory() {
        统计 A = 90
        统计 B = 50
        返回 140  ← 错误!
    }

  第二步:PutIn(B, 10)
    lock(B)
    B = 60
    unlock(B)

最终状态:
  A = 90
  B = 60
  总库存 = 150(恢复正常)

问题出在哪里?

在 TakeOut 和 PutIn 之间,存在一个"半完成"的中间状态。 另一个线程在这个窗口期看到了一个不可能的状态——10 箱货已经从 A 取出,但还没放入 B,它们仿佛凭空消失了。

3.4 真正的问题

很多人第一反应是:"那我加一把大锁不就行了?"

但真正的问题不在于锁多锁少,而在于:

TakeOut 自己决定了什么时候加锁、什么时候解锁,调用者完全无法控制。

当 TakeOut 返回时,锁已经被释放。Transfer 没有办法说:"先别释放,我后面还有一步操作。"

这就是锁的第一个特性:锁的获取和释放由函数内部控制,外部无法干预。

这意味着 TakeOut() 和 PutIn() 这两个正确函数不能被直接组合。要实现 Transfer,你只能:

cpp

void Transfer(Inventory& A, Inventory& B, int count) {
    // 必须重写,在外部统一管理锁
    lock(A.mutex);
    lock(B.mutex);
    
    A.quantity -= count;
    B.quantity += count;
    
    unlock(B.mutex);
    unlock(A.mutex);
}

或者把原来的函数拆成不带锁的内部版本,然后由调用方统一控制锁:

cpp

void TakeOutInternal(Inventory& A, int count);  // 不加锁
void PutInInternal(Inventory& B, int count);    // 不加锁

void Transfer(Inventory& A, Inventory& B, int count) {
    lock(A.mutex);
    lock(B.mutex);
    TakeOutInternal(A, count);
    PutInInternal(B, count);
    unlock(B.mutex);
    unlock(A.mutex);
}

不管哪种方案,你都必须重新设计。原来的 TakeOut 和 PutIn 模块没有被复用,你反而要去修改它们、拆分它们、或者暴露它们的内部锁。


四、什么是真正的模块化?

要理解锁为什么失败,我们需要先理解什么是成功的模块化。

4.1 可组合的函数

下面这些函数有一个共同特点:

cpp

sort(array);
int len = strlen(str);
printf("Hello");

它们可以自由组合:

cpp

sort(array);
printf("Sorted: %s\n", array);
int len = strlen(array);

无论怎么组合,结果都是正确的。你不需要知道 sort 内部做了什么,也不需要修改 printf 的实现。

这就是 Composability(可组合性)——模块化的核心属性。

4.2 锁函数为什么不可组合?

回到前面的例子:

cpp

TakeOut(A, 10);   // 内部管理锁
PutIn(B, 10);     // 内部管理锁

这两个函数单独看都是"正确"的,但组合之后:

  • TakeOut 在返回前释放了锁

  • 中间状态暴露给外界

  • PutIn 此时还没来得及执行

锁的释放时机被封装在函数内部,而这个时机恰好破坏了整体操作的一致性。

就像乐高积木:

  • 普通函数是标准积木,可以自由拼接

  • 带锁的函数像是每块积木都自带一个弹簧机关,单独玩没问题,但两块拼在一起时,弹簧会互相干扰,你必须拆开积木重新调整

4.3 Simon Peyton Jones 的洞见

Simon 指出:锁把并发控制和业务逻辑耦合在了一起。

一个函数如果内部自己管理锁,它就同时承担了两个职责:

  1. 业务逻辑(拿货、放货)

  2. 并发控制(何时加锁、何时解锁)

这两者耦合在一起,导致函数无法被自由组合。这才是锁最大的失败。


五、Chromium 的答案:从"保护共享"到"避免共享"

理解了锁的根本问题之后,再来看 Chromium 的设计选择,一切就豁然开朗了。

5.1 核心思想:与其保护共享,不如避免共享

Chromium 的并发模型建立在一个核心原则之上:

与其让很多线程共享一个对象,用锁来保护;
不如让一个对象只属于一个执行序列,通过消息传递来通信。

具体做法是:

  • 把对象绑定到特定的线程或 Sequence(执行序列)

  • 其他线程想操作这个对象?发消息,而不是直接访问

  • 对象的实际修改永远发生在它所属的线程/Sequence 上

这就是 Message Passing(消息传递) 和 Thread Affinity(线程归属) 的核心理念。

5.2 一个具体的例子

假设 UI 线程上有一个标签页对象 TabStrip,IO 线程需要修改它的标题:

传统加锁方案:

cpp

class TabStrip {
    std::mutex mutex_;
    std::string title_;
    
public:
    void SetTitle(const std::string& title) {
        std::lock_guard<std::mutex> lock(mutex_);
        title_ = title;
    }
};

// IO 线程直接调用
tab_strip->SetTitle("New Title");  // 阻塞等待锁

这种方式的问题是:

  • IO 线程可能阻塞等待 UI 线程释放锁

  • UI 线程可能阻塞等待 IO 线程释放锁(死锁风险)

  • SetTitle 的实现细节(加锁)暴露给调用者

Chromium 的消息传递方案:

cpp

// IO 线程想修改 TabStrip 的标题
// 不直接访问,而是投递一个任务到 UI 线程
content::GetUIThreadTaskRunner({})->PostTask(
    FROM_HERE,
    base::BindOnce(&TabStrip::SetTitle, 
                   base::Unretained(tab_strip),
                   "New Title"));

关键区别:

  • IO 线程不直接访问 TabStrip 的数据

  • SetTitle 保证在 UI 线程上执行

  • 没有锁,没有阻塞,没有死锁风险

  • TabStrip 内部不需要加锁,因为它只在 UI 线程上被访问

5.3 Sequence:单线程的幻觉

在 Chromium 中,Sequence 是一个重要的抽象概念。

Sequence 是一个虚拟的执行序列。投递到同一个 Sequence 的所有任务,会严格按顺序执行,永远不会并发。

可以把 Sequence 理解为"单线程的幻觉":

  • 同一个 Sequence 的任务按顺序执行

  • 不同 Sequence 之间可以并行

  • 一个线程可以管理多个 Sequence

这个概念的关键价值在于:如果你把对象绑定到一个 Sequence,那么你就不需要锁。 因为所有对该对象的访问都是序列化的。

5.4 Sequence 天然支持模块化

回到我们的仓库例子。如果使用 Sequence:

cpp

// 把仓库操作绑定到同一个 Sequence
task_runner->PostTask(FROM_HERE, base::BindOnce([]{
    TakeOut(A, 10);  // 不带锁的版本
    PutIn(B, 10);    // 不带锁的版本
}));

由于整个 Lambda 在同一个 Sequence 上执行,执行期间不会有其他任务插入。外界只能看到:

  • 执行前:A=100, B=50

  • 执行后:A=90, B=60

中间状态完全不可见。

更重要的是:TakeOut 和 PutIn 终于可以自由组合了!不需要暴露内部锁,不需要重写函数,不需要拆分逻辑。这就是模块化。


六、并不意味着锁被完全抛弃

需要澄清的是:Chromium 并没有完全消灭锁。

在底层基础设施中,锁依然不可或缺:

  • 内存分配器

  • 任务调度器

  • 引用计数(base::RefCountedThreadSafe)

  • 缓存系统

这些底层组件需要处理真正的并发访问,锁仍然是最合适的工具。

Chromium 的设计哲学是分层对待:

层级并发策略使用场景
业务逻辑层Sequence + Message PassingUI 组件、网络请求处理、扩展管理
基础设施层Lock + Atomic内存管理、调度器、引用计数

业务逻辑层尽量消除对锁的需求,让开发者不需要手动处理并发;基础设施层在必要时使用锁,由少数专家精心维护。

这种分层思想,才是 Chromium 并发模型的核心智慧。


七、总结

很多人认为 Chromium、Linux Kernel、Rust 等现代项目减少锁的使用,是因为锁会导致死锁、性能差或者容易写错。这些问题确实存在,但都属于"症状"。

Simon Peyton Jones 指出的真正核心在于:锁把并发控制和业务逻辑耦合在了一起。

一个函数如果内部自己管理锁,它可能单独是正确的;但一旦需要与其他函数组合,就会暴露出中间状态,调用者不得不重新设计锁的粒度、作用范围和顺序,最终导致模块失去可组合性。

Chromium 的设计——SequenceChecker、TaskRunner、PostTask、Thread Affinity——本质上都是在回答同一个问题:

与其让很多线程共享一个对象,用锁来保护;
不如让一个对象只属于一个执行序列;
与其用锁保护共享,不如尽量避免共享。

这也是现代并发设计越来越推崇 Message Passing(消息传递)、Actor Model(Actor 模型) 和 Sequence(执行序列) 的原因。它们并不是完全取代锁,而是通过减少共享状态,让业务逻辑能够像普通函数一样自然地组合,从而降低复杂度,提高大型工程的可维护性。


附:深入阅读 Chromium 源码的建议

如果你对 Chromium 的并发模型感兴趣,以下几个文件是很好的起点:

文件内容
base/sequence_checker.hSequenceChecker:在 DEBUG 模式下检查当前代码是否运行在正确的 Sequence 上
base/task_runner.hTaskRunner 接口:PostTask 的入口
base/lock.hLock 和 AutoLock 的实现,观察底层锁的使用方式
content/public/browser/browser_thread.hBrowserThread::UI / IO 等线程定义
base/threading/thread_local.h线程局部存储,理解 Thread Affinity 的底层支持

理解这些组件如何协同工作,你会对"避免共享优于保护共享"有更深的体会。

Claude Mythos如何重塑AI安全研究范式 大模型在网络安全领域的应用正从辅助工具迈向自主决策核心。随着推理能力、符号执行与红蓝对抗训练的深度融合,前沿模型已能完成端到端漏洞挖掘、PoC生成与风险建模。这类能力突破不仅依赖参数规模,更源于训练范式升级(预训练-强化学习-推理时扩展)、动态MoE架构优化及认知层安全对齐。其技术价值体现在将传统数日级人工渗透压缩至分钟级闭环,并支撑黑盒固件逆向、零日狩猎与影子IT测绘等高复杂度场景。本文聚焦Claude Mythos Preview在真实攻防中的工程落地逻辑与能力边界。 阅读详情

相关推荐

Mythos:首个可规模化执行端到端漏洞利用的AI安全模型

漏洞利用(Exploit)是网络安全的核心能力之一,传统上依赖人工逆向、模糊测试与符号执行等专业工具链,门槛高、周期长、难以规模化。随着大语言模型推理能力与攻防对抗训练范式的突破,新一代AI安全模型正从‘辅助发现漏洞’迈向‘自主生成可复现exploit’。Mythos代表了这一范式跃迁的关键节点——它融合动态推理调度(CyberScaffold)、攻防沙箱强化学习与多层级工具调用能力,在无需人工干预前提下,对源码或二进制输入直接输出POC级利用代码。其技术价值在于将漏洞利用工程化、API化、低成本化,适用于

weixin_33691700的博客 355

多模态自主智能体与树搜索:让AI真正‘看懂’并操作网页

网页自动化本质是人机交互语义对齐问题——传统基于XPath或文本的RPA难以应对响应式布局、动态加载和空间指令等现实挑战。多模态自主智能体通过融合视觉理解(坐标/颜色/相对位置)与HTML结构解析,构建‘眼脑手’协同的认知闭环;树搜索则将任务求解建模为可回溯、可剪枝的状态空间探索,显著提升容错性与鲁棒性。该技术路径已在电商比价、政务填报、医疗挂号等真实场景验证,成为解决‘按钮可见但模型不可达’‘页面跳转即中断’等顽疾的关键范式,也是当前Web Agent工程落地的核心架构选择。

cuanji3287的博客 372

Web安全攻防入门:从SQL注入到XSS,构建应用安全防线

Web安全是保障互联网应用数据与功能完整性的关键技术领域,其核心在于理解数据在客户端与服务器端之间的信任边界与验证机制。从技术原理看,攻击者常通过构造恶意输入,利用应用程序对用户数据信任过度或验证不足的缺陷,实现非授权操作。例如,SQL注入通过将恶意SQL代码嵌入用户输入,欺骗后端数据库执行非预期命令;而XSS(跨站脚本攻击)则通过注入恶意脚本到网页中,在用户浏览器端执行以窃取会话信息。这些漏洞的技术价值在于揭示了输入验证、输出编码与会话管理在安全体系中的基础性地位。在应用场景上,无论是电商、社交还是企业系

weixin_33672109的博客 358

AI浏览器架构安全缺陷与钓鱼攻击防御重构

浏览器作为现代Web应用的核心入口,其安全架构设计直接关系到用户数据和系统安全。传统浏览器通过多进程隔离、沙箱机制和安全扩展生态构建了纵深防御体系。然而,为满足AI自动化场景对性能和资源效率的极致需求,新兴的AI浏览器在架构层面进行了深度裁剪,这无意中引入了新的攻击面。攻击者可利用沙箱弱化、无头模式UI缺失、自动化接口暴露等缺陷,构造难以被传统方案检测的钓鱼攻击。本文聚焦于AI浏览器特有的安全风险,深入剖析其架构缺陷被利用的攻击链,并提供从容器隔离、配置加固到监控告警的全方位防御方案,帮助开发者在享受AI浏

weixin_30367873的博客 337

Web安全入门:从HTTP协议到Burp Suite抓包实战指南

HTTP/HTTPS协议是Web通信的基石,它定义了客户端与服务器之间请求与响应的标准格式。理解其工作原理是掌握Web安全的第一步,因为许多安全漏洞都源于对协议细节的滥用或错误处理。通过中间人代理技术,安全人员可以拦截、分析并修改网络流量,从而深入理解应用行为、发现潜在弱点。这种技术为安全测试、漏洞挖掘和渗透测试提供了核心支持,广泛应用于应用安全评估、漏洞验证和协议分析等场景。本文以Burp Suite这一行业标准工具为例,结合抓包与代理技术,详细演示如何搭建测试环境、配置代理并开展基础的安全测试实践,帮助

weixin_30420305的博客 440

M2DGR数据集在一些SLAM框架上的配置与运行:ORB-SLAM系列、VINS-Mono、LOAM系列、FAST-LIO系列、hdl_graph_slam

为了说明以上这些SLAM框架的测试与数据集适配,以M2DGR数据集为例进行各自的配置与运行,方便我以后适配自己的数据集,运行的SLAM框架包括:ORB-SLAM2、ORB-SLAM3、VINS-Mono、A-LOAM、LeGO-LOAM、LIO-SAM、LVI-SAM、FAST-LIO2、FAST-LIVO、Faster-LIO、hdl_graph_slam。实验基于Ubuntu20.04,其中ORB、VINS-Mono、和LOAM系列的安装参考我以前的博客,有详细的安装方法,其他的框架在后面会简单介绍一下

zardforever123的博客 1万+

软件方法第2章:方法与过程的辨析及Electron内存治理实践

在软件工程实践中,“方法”与“过程”是两个经常被混用的维度,但二者本质不同:过程管时间,方法管质量。理解这一原理,是保证项目从需求推导到设计落地不跑偏的前提。建模语言如UML只是表达工具,并不等于分析本身。这种认知框架同样适用于具体工程难题——例如Electron应用打包后内存持续攀升,根因往往不在于GC参数,而在于对象生命周期管理混乱。通过梳理对象引用关系、区分长短期生命周期对象,并结合Node.js垃圾回收机制与--expose-gc参数,可以实现主动GC与内存阈值监控的有效配合。从方法论到工程实践,《

weixin_34779181的博客 143

【数据库】银行/信贷业务测试工作中涉及的数据库表格

银行/信贷业务测试工作中涉及的数据库表格,金融信贷测试人必看!

孤之鹜的博客 1169

WebGoat2026年版本(全10个模块另附其他模块)通关教程

本文简要介绍了WebGoat安全测试平台的部署和使用方法。主要内容包括:1)环境配置(Java23+Maven3.9.11)和启动步骤;2)HTTP基础任务,通过BurpSuite抓包分析POST请求;3)HTTP代理任务,要求修改请求方法和添加特定头信息;4)开发者工具任务,使用控制台获取随机数和网络请求中的数值;5)CIA三要素测验题。文章提供了具体操作截图和Python请求示例,帮助读者完成各项安全测试任务,适合作为Web应用安全测试的实操参考手册。

csdnkazusa的博客 1356

从Zemax到Speos:HUD设计数据无缝迁移避坑指南(含STEP文件精度验证)

本文详细介绍了从Zemax到Speos的HUD设计数据无缝迁移方法,重点解决Zernike曲面参数保真、虚拟厚度设置和坐标系对齐等核心问题。通过STEP文件精度验证和工程化解决方案,帮助工程师避免数据迁移中的常见陷阱,提升HUD系统设计效率。适用于Ansys Zemax和Ansys Speos用户,优化光学性能验证流程。

h6i7j8的博客 1063

STM32CubeMX + HAL库避坑指南:为什么你的代码总在SystemClock_Config卡住?

本文深入剖析了STM32开发者在使用STM32CubeMX和HAL库时,代码在SystemClock_Config函数中卡死的根本原因。文章不仅指出硬件时序、Flash延迟配置等常见陷阱,更提供了从硬件设计、软件容错到深度调试的系统性解决方案,帮助开发者构建鲁棒的时钟初始化策略,彻底告别启动卡顿问题。

bb456的博客 927

Chrome 扩展安全攻防实录:从攻击面到防御实践

本文系统剖析Chrome扩展安全风险,涵盖其架构组成、权限模型与通信机制,梳理权限滥用、脚本注入、消息信任漏洞等攻击面,结合XSS提权、伪造消息、供应链攻击等典型案例,提出最小权限、输入校验、CSP策略、依赖管理等防御体系,并提供静态检查、动态调试等审计实践。展望Manifest V3下安全演进方向,为开发者与安全研究者提供全面防护指南。

2401_84466325的博客 180

基于STM32F103C8T6的智能蓝牙手环系统设计与实现

摘要:本文设计并实现了一款基于STM32F103C8T6单片机的智能蓝牙手环系统。该系统集成了ADXL345加速度计、DS18B20温度传感器、plusesennor心率模块和BT06蓝牙模块,实现了心率(±2bpm)、体温(±0.5℃)、步数(±3%)等健康数据的实时监测与显示。通过OLED屏提供人机交互界面,支持蓝牙APP远程控制,具备自动步数清零、异常提醒等功能。测试表明系统各项功能均达到设计要求,响应时间0.1-0.5秒,心率检测准确率98%,体温检测准确率99%,功耗50mA(工作)/10mA(待

3254968421的博客 205

Chrome 诡异问题|地址栏输入[baidu.com](https://baidu.com),页面却显示 Google 主页,无痕模式、设置页空白故障解决

今天遇到一个很奇怪的 Chrome 故障:地址栏明明输入baidu.com,打开页面却是 Google 首页,chrome://settings设置页面空白,无痕窗口访问百度同样黑屏,最终通过管理员 PowerShell 执行ipconfig /flushdns、netsh winsock reset并重启电脑修复。

m0_74451345的博客 97

YOLOv10改进 | 代码逐行解析(三) | YOLO中的Mosaic增强详解(新手入门必读系列)

本文给大家带来的是YOLOv10中的Mosaic增强代码的详解,可能有部分人对于这一部分比较陌生,有的读者可能知道Mosaic增强但是不知道其工作原理,具体来说Mosaic增强就是指我们的数据集中的图片在输入给模型之前的一个处理过程(我们的图片并不是直接就输入给模型了,大家的训练结果中的结果检测图片大家可以看到数据集中多个图片会组合在一起这就是简单的Mosaic增强),下面我就来讲解一下其在YOLOv10中工作原理和代码定义,下面图片为一个Mosaic增强后的图片。​。

Snu77的博客 2075

遗传算法(GA)全面解析:从生物基础到工程实践

本文全面解析了遗传算法(GA),从其生物基础到工程实践应用。遗传算法模拟自然进化过程,通过选择、交叉和变异等操作在解空间中高效搜索最优解。文章详细介绍了算法的生物学基础(达尔文进化论、孟德尔遗传定律)、基本概念(种群、个体、基因等)和核心思想。重点阐述了遗传算法的数学模型,包括编码机制、适应度函数设计、遗传算子(选择、交叉、变异)以及关键控制参数。最后提供了一个完整的Python实现示例,展示了遗传算法求解函数最大值问题的具体应用。该算法具有群体搜索、概率导向、无需梯度等特点,适用于各类复杂优化问题。

qq_42212808的博客 1175

【AI工具集】搭建Chrome Use替换Trae/CodeBuddy的Browser Use/浏览器控制/agent-browser

# 【AI工具集】搭建Chrome Use支持小龙虾/Trae/CodeBuddy的Browser Use/浏览器控制/agent-browser替换 ## 结论先行 **目的:** 在 Chrome 浏览器安装 chrome-use 扩展插件,打通浏览器和agent工具的桥联。可以用在openclaw 小龙虾,Trae , CodeBuddy(Work版本一样),稳定 & 深度 控制页面元素级内容,不受后台 / 浏览器缩放 / 桌面分辨率变化影响 / 兼容本地和云端LLM模型 ## 背景 最近在做AI自

刻痕 206

(王道计算机组成原理笔记)第一章计算机系统概述-第二节:计算机系统层次结构 1(计算机系统组成、计算机硬件)

文章目录一:冯诺依曼体系结构(1)存储程序计算机(2)层次结构二:计算机硬件概述(1)存储器A:存储元、存储单元、存储体、存储字和存储字长B:MAR 一:冯诺依曼体系结构 在冯诺依曼体系结构中,计算机的硬件主要有**存储器,运算器,控制器,输入和输出设备(也叫做I/O设备)**组成。 (1)存储程序计算机 冯诺依曼体系结构也叫做存储程序计算机,计算器和计算机的唯一区别就是计算器是不能编程的,只能做电路板中设定好的固定的运算。 这也就意味着计算器本质就是一个不能编程的计算机,其在硬件层面已经将逻辑写死,如果

快乐江湖的博客 1万+

Chrome 扩展安全攻防实录:从权限滥用到供应链投毒

汇总开发者自查清单与使用者风险识别要点,给出可执行的落地建议。

FJ39SfgYS的博客 205

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

墨墨助记 Moji v0.3.0 升级|Chrome 网页离线查词,收藏生词也能留下原句

墨墨助记 Moji v0.3.0 为桌面 Chrome 带来网页离线查词:双击生词或划选短语,点一下放大镜,就能在原文旁看释义、助记和例句。连接墨墨后,可把生词、网页原句和中文译文一起收藏,还能分别设置参与高亮的复习词本和新词的收藏去向。文中用 abandon 演示完整流程。

长路漫漫的歇脚处 217

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Chrome 内存泄漏诊断指南:从现象到根因的完整排查路径

诊断流程回顾:现象 → 基线 → 趋势 → 快照 → 引用链 → 修复 → 验证工具选择建议与学习资源。

qq_44304677的博客 289

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Chrome 内存泄漏诊断指南:从现象定位到根因排查

本文系统解析前端内存泄漏的成因、诊断与预防,涵盖堆栈内存模型、V8垃圾回收机制及常见泄漏场景(如未解绑事件、定时器、闭包滥用等)。通过Chrome DevTools性能面板、堆快照对比、分配时间线等工具,结合“五步定位法”实战排查,剖析路由切换、虚拟列表、WebSocket缓存等典型案例。强调编码规范、生命周期管理与工程化监控,提出“先确认、再定位、后验证”的方法论,助力开发者提升应用稳定性与性能。

2401_84488651的博客 303
上一篇: 当机器人学会后空翻,我们离真正的智能还有多远?
下一篇: 为什么 Chromium 如此推崇异步非阻塞?——彻底搞懂同步、异步、阻塞、非阻塞
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ปรัชญา แค้วคำมูล

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值