HTTP客户端实现 - 百度首页探寻
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146#include <sys/socket.h>#include <sys/types.h>#include <netdb.h>#include <cstring>#include <unistd.h>#include <cerrno>#include <c...
getaddrinfo 查找网络IP
一、网络地址解析的必要性在网络通信中,应用程序通常需要通过域名(如www.example.com)而非直接使用 IP 地址(如93.184.216.34)来定位目标主机,同时需要通过服务名(如http)而非直接使用端口号(如80)来指定通信端口。这种抽象带来了以下核心需求: 用户友好性:人类更容易记忆域名而非数字 IP 协议兼容性:需同时支持 IPv4 与 IPv6,避免硬编码地址类型 服务灵活性:服务端口可能动态分配,通过服务名解析更可靠 网络拓扑适应:同一域名可能对应多个 IP(负载均衡场景),需支持多地址选择 传统地址解析方法(如gethostbyname、getservbyname)存在明显局限性:仅支持 IPv4、无法统一处理主机名与服务名、线程安全性差。getaddrinfo作为 POSIX 标准接口,完美解决了这些问题,是现代 C++ 网络编程的首选地址解析方案。 二、getaddrinfo 函数getaddrinfo是一个统一的地址解析接口,可同时处理主机名→IP 地址、服务名→端口号的解析,并返回可直接用于socket调用的地址结构。 2.1 函数原...
警惕 “虚假精通”,守住技术人的核心竞争力
导言在 AI 工具如 Claude、ChatGPT 日益渗透到软件开发全流程的当下,Playtechnique 的《AI Doesn't Lighten the Burden of Mastery》像一剂清醒剂,戳破了 “AI 能帮我们跳过学习、直接掌握技术” 的幻象。文章没有否定 AI 的价值,却直指一个更本质的问题:AI 能生成 “形似” 的优质代码,却无法替我们完成 “理解” 与 “思考” 的核心工作;它能减轻机械性的体力负担,却永远无法替代 “精通” 所需的认知投入。这篇短文让我对 “AI 时代如何做技术” 有了更深刻的反思。 在 C++ 开发领域,AI 工具同样展现出强大的代码生成能力 —— 从类定义、模板函数到 STL 容器用法,甚至多线程同步逻辑,AI 都能快速输出 “形似规范” 的代码。但结合 playtechnique 的观点再看 C++ 开发场景,会发现 “虚假精通” 的陷阱更隐蔽、危害也更大:C++ 的内存管理、指针操作、模板元编程等底层特性,恰恰是 AI 最易出错却最难被察觉的地方。这篇感悟将聚焦 C++ 开发,聊聊如何在借助 AI 提升效率的同时...
Netty 源码研读 Phase0:准备环境、拉取源码与跑通 echo
你下定决心读 Netty 源码,兴冲冲 clone 下来、打开 IDE——然后卡住三连:clone 哪个版本?为什么满屏模块不知道 import 哪个?官方那个 echo 例子到底怎么跑起来?本文把这套地基一次铺平,让你后面 30 篇能直接点进源码、能跑、能对照。 本文所有命令与现象均经过实跑验证:源码在沙箱(JDK 17)编译跑通 echo,并在读者本机(Windows + IntelliJ + Microsoft Build of OpenJDK 11.0.32)完整复现——包括下文列出的每一处编译/运行坑。 一、Phase0 是地基,不是源码分析 是什么:Phase0 不分析任何 Netty 内部机制,只解决一件事——环境就位:版本锁定、IDE 能跳转、最小例子能跑。 坑:很多人一上来就读 ChannelPipeline 源码,结果连代码都没 clone 对版本,类名对不上、行号对不上,越读越像在背天书。 本质一句话:读源码的前提是"源码在你机器上能点得进去、能跑起来",否则全是脑补。 二、锁定版本:为什么是 netty-4.1.110....
C++ 断言(assert)机制
一、assert 宏的基本语法与工作机制断言是 C++ 标准库提供的调试工具,核心通过头文件(兼容 C 的<assert.h>)中的assert宏实现,其本质是条件检查宏,仅在调试阶段生效。 1.1 核心语法assert宏接收一个布尔表达式作为参数,语法如下: 12345678910111213#include <cassert> // 必须包含的头文件int main() { int* ptr = new int(10); // 检查指针是否非空(调试阶段生效) assert(ptr != nullptr); delete ptr; ptr = nullptr; // 此时断言会失败(指针已置空) assert(ptr != nullptr); return 0;} 1.2 工作机制与 NDEBUG 宏assert的行为完全由 **NDEBUG宏 **("No Debug")控制,这是 C++ 标准规定的编译级开关: 调试模式(未定义NDEBUG): ...
Redis 热 Key 问题
一、定义热 Key 是 Redis 高并发场景中,访问频率显著高于其他键的特殊键,其核心问题是 “单键请求过度集中于某一 Redis 节点”,导致该节点 CPU、内存资源占用飙升,进而引发节点响应延迟、命令阻塞,甚至拖累整个集群稳定性。 1.1 核心判定特征 访问频率:单键 QPS(每秒请求数)占集群总 QPS 的 10% 以上,或单键每秒访问次数持续超过 1000 次(具体阈值可根据集群规模调整,小集群可适当降低); 节点资源占用:热 Key 所在节点的 CPU 使用率(系统 CPU + 用户 CPU)持续超过 80%(Redis 为单线程模型,CPU 满负荷会阻塞所有命令执行),或该节点内存占用远超集群内其他节点; 业务影响范围:热 Key 关联核心功能,若其所在节点故障,会导致大范围业务不可用,而非局部功能异常。 二、识别方法识别的核心目标是 “精准定位热 Key 及所在节点”,常用方法按 “轻量临时→专业长期” 分为两类: 轻量临时识别(依赖 Redis 原生命令)步骤 1:获取集群性能基线 执行redis-cli info stats命令,查看total_co...
Redis String类型大Key问题
一、引言在Redis的实际应用中,大Key问题是影响性能和稳定性的重要因素之一。从系统资源消耗维度分析,此类问题主要体现在三个层面:其一,内存管理层面,单 Key 占据过量内存空间,致使内存碎片化程度加剧,频繁触发内存淘汰机制,降低存储效率;其二,网络传输层面,大 Key 的读写操作产生大规模数据包,极易造成网络带宽饱和,例如单次读取 100MB 大 Key 会完全占用对应带宽资源;其三,CPU 资源层面,大 Key 的序列化与反序列化过程,以及复杂数据结构的遍历操作(如大列表遍历),均会消耗大量 CPU 资源,进而影响其他指令的执行效率。 二、大Key定义与危害分析2.1 定义对于String类型,通常认为超过10KB的键值对就属于大Key。在我们的测试环境中,user_session_1002键的大小为325,001字节,明显属于大Key范畴。 2.2 危害 内存不均:大Key会导致Redis实例内存分布不均,影响集群的负载均衡 网络压力:读取大Key会产生大量网络流量,可能阻塞网络 性能下降:对大Key的操作(特别是DEL操作)可能导致Redis阻塞,影响整体QPS 服务阻...
基于Trie树的词频统计与前缀匹配
一、为什么需要 Trie 树?—— 先搞懂核心价值在开始写代码前,我们先明确 Trie 树的 “不可替代性”: 数据结构 插入 / 查询复杂度 前缀匹配能力 内存效率(重复前缀) 适用场景 哈希表(unordered_map) 平均 O (1) 不支持 低(存完整字符串) 单键精准查询(如缓存) 红黑树(map) O(log n) 支持(遍历) 低 有序键值对查询 Trie 树 O (k)(k 为字符串长度) 原生支持 高(前缀共享) 前缀相关操作(自动补全) 简单说:如果你的需求涉及 “前缀”(如输入 “app” 要提示 “apple”“application”),Trie 树是最优解之一。 本文实现的 Trie 树将包含以下核心功能: 单词插入(自动统计重复单词的出现次数) 词频查询(返回单词出现次数,0 表示不存在) 前缀匹配(返回所有以指定前缀开头的单词,支持字典序 / 词频排序) 单词删除(智能回收无用节点,不破坏共享前缀) 整体清空(安全释放所有内存,避免泄漏) 二、代码结构设计 —— 工程化拆分为了保证代码的可维护性,...
Trie 树核心原理
一、Trie 树定位Trie 树(前缀树 / 字典树)是专为字符串设计的树形结构,核心价值是通过 “前缀共享” 减少内存冗余,同时实现 O (k)(k 为字符串长度)的插入 / 查询效率,尤其适合 “前缀相关场景”(如自动补全、拼写检查)。 二、核心结构:节点设计与前缀共享1. 节点结构体Trie 的最小单元是节点,需存储子节点映射和单词结尾标记,C++ 中用结构体实现最简洁: 123456789struct TrieNode { // 子节点:两种实现方案(按需选择) // 方案1:数组(仅适用于固定小字符集,如小写字母,速度快) TrieNode* children[26] = {nullptr}; // 方案2:哈希表(字符集不确定时用,如含数字/符号,灵活) // unordered_map<char, TrieNode*> children; bool isEnd = false; // 标记当前节点是否为某单词的结尾(避免前缀误判)}; 根节点是TrieNo...
C/C++ 中两种结构体 typedef 定义的差异与实践
导言在 C 和 C++ 编程中,结构体(struct)是组织复杂数据的核心工具,而 typedef 则常用于简化类型名、提升代码可读性。实际开发中,我们常会见到两种结构体 + typedef 的定义方式:typedef struct Person{} Person; 与 typedef struct {} Person;。这两种写法看似相似,却因语言特性(C/C++ 差异)和结构体标签(tag)的存在与否,在使用场景、功能限制上有显著区别。 一、基础认知:结构体标签与 typedef 的作用在深入差异前,需先明确两个核心概念: 结构体标签(tag):紧跟 struct 后的标识符(如 struct Person 中的 Person),是结构体的 “原生名称”,仅在 struct 关键字后生效。 typedef 别名:通过 typedef 为类型(包括结构体)定义的简化名称(如 Person),可直接作为类型名使用。 C 和 C++ 对 “结构体标签” 的处理规则不同,这是两种定义方式差异的根源 ——C 语言中,结构体必须通过 struct 标签 或 typede...
Redis RDB 持久化
一、RDB 概念解析Redis 数据库的 RDB(Redis Database)持久化机制,本质上是一种将内存数据以二进制快照形式存储至磁盘的技术方案。该机制通过创建一个名为dump.rdb的文件(默认文件名),将 Redis 内存中的全部数据进行序列化保存。例如,当 Redis 实例包含 10,000 条数据记录时,RDB 机制会将这些数据完整保存至快照文件,在系统重启时通过加载该文件实现数据恢复。 二、核心技术原理RDB 持久化的实现过程主要涉及以下两个关键步骤: 子进程创建(fork 机制):在触发 RDB 快照生成时,Redis 利用操作系统的fork机制创建一个子进程。此时,父进程继续处理客户端的读写请求,确保业务连续性;而子进程则负责将内存数据写入 RDB 文件,这种分离设计有效避免了对业务处理的阻塞。 写时复制(Copy-On-Write,COW):在子进程执行数据写入操作期间,若父进程需要修改内存中的数据,系统会采用写时复制策略。具体而言,父进程将待修改的数据复制一份,在新副本上进行修改操作,而子进程继续读取原始数据写入 RDB 文件。通过这种方式,能够确保 RD...
Redis AOF 持久化机制
导言在分布式计算架构中,Redis 作为内存数据库的典型代表,其数据持久化机制构成了系统容错性与数据一致性保障的核心技术支撑。在 Redis 提供的 RDB(Redis Database)快照持久化与 AOF(Append-Only File)日志追加持久化两种核心策略中,AOF 机制凭借其基于操作日志的增量式数据记录模式,在数据完整性保障方面展现出独特优势。 一、AOF 持久化机制的理论模型与实现架构AOF 持久化机制遵循 "Write-Ahead Logging"(预写日志)设计范式,通过顺序追加的方式记录数据库写操作,从而构建可回溯的历史操作序列。该机制在运行时经历命令缓存、磁盘同步、日志优化三个核心处理阶段,各阶段通过协同工作实现数据可靠性与系统性能的动态平衡。 1. 命令缓存层:基于 RESP 协议的操作记录在 Redis 执行写操作过程中,系统将 SET、HSET、LPUSH 等指令按照 RESP(Redis Serialization Protocol)协议标准进行序列化,并暂存于内存级 AOF 缓冲区。这种设计有效规避了频繁磁盘 I/...
Redis 缓存三大故障 - 缓存穿透
导言在分布式系统中,Redis 作为高性能分布式缓存,可有效减轻数据库压力、提升接口响应速度,但高并发场景下,缓存雪崩、缓存击穿、缓存穿透三类异常易引发系统稳定性问题。 一、缓存穿透 ——“不存在数据” 的持续穿透1. 核心定义缓存穿透是指查询的数据在缓存和数据库中均不存在(如查询不存在的 ID、非法参数),导致每次请求都穿透缓存直接查询数据库,且由于缓存无法存储 “不存在的数据”,后续相同请求会持续穿透,造成数据库无效查询压力激增的现象。 核心特征:区别于前两类异常,其关键在于 “查询无结果数据”,缓存无法拦截,请求持续打向 DB。 2. 触发条件缓存穿透的发生源于两类场景: 非法请求攻击:恶意用户构造非法参数(如负数 ID、超长字符串)发起大量查询,这类数据在缓存和 DB 中均不存在; 业务空数据查询:正常业务场景中,部分查询天然无结果(如查询已删除的用户、未创建的订单),且未做缓存处理。 3. 解决方案对比 解决方案 实现逻辑 优点 缺点 适用场景 空值缓存 查询 DB 无结果时,将 “空值”(如空字符串、默认对象)存入 Redis,并设置较短过期时间(如...
Redis 缓存三大故障 - 缓存击穿
导言在分布式系统中,Redis 作为高性能分布式缓存,可有效减轻数据库压力、提升接口响应速度,但高并发场景下,缓存雪崩、缓存击穿、缓存穿透三类异常易引发系统稳定性问题。 一、缓存击穿 —— 热点数据 “过期瞬间” 的单点突破1. 核心定义缓存击穿是指某一 “热点数据”(高并发访问的单一数据)的缓存过期失效瞬间,大量并发请求同时查询该数据,由于缓存已无对应数据,所有请求直接穿透至数据库,导致数据库针对该热点数据的查询压力骤增、甚至出现查询超时的现象。 核心特征:区别于缓存雪崩,其关键在于 “单个热点数据失效”,影响范围为 “局部”(仅该热点数据相关查询)。 2. 触发条件缓存击穿的发生需同时满足两个条件: 热点数据缓存过期:某一数据访问量极高(如每秒数千次查询),且其 Redis 缓存恰好过期; 无预热机制的突发热点:突发高并发请求集中访问某一数据(如临时热门内容),而该数据未提前缓存,导致请求直接打向 DB。 3. 解决方案对比 解决方案 实现逻辑 优点 缺点 适用场景 互斥锁(分布式锁) 缓存失效时,仅允许一个请求获取锁并查询 DB,更新缓存;其他请求等待锁释...
Redis 缓存三大故障 - 缓存雪崩
导言在分布式系统中,Redis 作为高性能分布式缓存,可有效减轻数据库压力、提升接口响应速度,但高并发场景下,缓存雪崩、缓存击穿、缓存穿透三类异常易引发系统稳定性问题。 一、缓存雪崩 —— 大量缓存 “集体失效” 的连锁反应1. 核心定义缓存雪崩是指某一时间段内,大量缓存数据同时过期失效,或缓存服务(如 Redis 集群)整体不可用,导致原本由缓存承接的高并发请求全部穿透至数据库,引发数据库压力骤增、甚至宕机,进而可能导致整个业务服务雪崩的现象。 核心特征:区别于其他异常,其关键在于 “批量失效 / 整体不可用”,影响范围为 “全局”(而非局部)。 2. 触发条件缓存雪崩的发生通常源于两类场景,满足任一即可触发: 缓存集中过期:大量缓存数据设置了相同或相近的过期时间(如统一设为 24 小时、固定时间点过期),到期后集体失效,请求失去缓存承接; 缓存服务不可用:Redis 集群因硬件故障、网络波动、内存溢出被系统终止等原因,出现整体宕机或无法访问,导致缓存层完全失效。 3. 解决方案对比 解决方案 实现逻辑 优点 缺点 适用场景 缓存过期时间加随机值 为...
Python property 数据管线:用声明式属性拦截构建 ETL 级数据流
一、为什么“数据”需要先过一道管线,而不是裸字段真实工程里,原始输入(接口返回的 dict、配置文件、CSV 行)往往很脏:字段类型不对、越界、缺失、需要单位换算、还要派生出新的指标。如果直接把脏值塞进对象字段,后面每一处使用都得重新做判空、判范围、判类型——坑多且分散。 Python 的 property 不只是 getter/setter 的语法糖,它是在“属性访问这一刻”插入逻辑的能力。这就天然适合做一条“访问即清洗 / 校验 / 派生 / 缓存”的数据管线:调用方写 r.temp_c、r.heat_index,看起来像读普通字段,背后却已经把脏数据挡在门外。 C++ 视角对照:C++ 没有语言级 property。要实现“访问即校验 + 派生”,要么手写一堆 getX()/setX()(啰嗦,且调用方要改写法),要么依赖 Qt 的 Q_PROPERTY 宏(仅 Qt 生态、需 moc 预处理),要么用 operator>> 做流式管线(在“读取时”校验,而非“访问属性时”)。Python 用 @property 把“管线...
Redis 哨兵模式(Sentinel)
导言哨兵模式(Sentinel)是 Redis 主从复制架构的 “高可用增强层”,通过分布式共识机制解决了主从复制中 “主节点宕机需手动切换” 的痛点,实现故障自动检测、主节点自动选举、从节点自动同步,是中小规模 Redis 集群(数据量 < 10GB、读多写少)的生产级高可用标准方案。 一、哨兵模式的核心定位与价值1.1 在理解哨兵前,需先明确其与主从复制的关系:主从复制负责 “数据同步”(主写从读、数据备份),但无法自动处理主节点故障; 哨兵负责 “高可用保障”(监控、故障转移、配置自动更新),是主从架构的 “大脑”,二者协同实现 99.99% 服务可用性。 1.2 哨兵模式的核心价值 彻底告别手动运维:主节点宕机后,无需人工干预,10-30 秒内完成故障转移 分布式容错:多哨兵节点共识判断,避免单点误判(如网络抖动导致的假宕机) 客户端透明路由:客户端可通过哨兵获取当前主节点地址,无需硬编码 IP / 端口 配置动态同步:故障转移后,自动通知所有从节点切换新主节点,更新同步关系 二、哨兵的核心功能与工作原理2.1 四大核心功能拆解 功能模块 具...
Python元类编程:type与__new__如何拦截类的诞生
一、先捅破一层窗户纸:类也是对象写过几年 Python 的人大多听过一句话——"一切皆对象"。但真把这句话吃透,往往要等到第一次被元类(metaclass)绊住脚。 看一段最朴素的代码: 12345678910class User: role = "member" def greet(self): return f"hi, I am a {self.role}"u = User()print(u.greet()) # hi, I am a memberprint(type(u)) # <class '__main__.User'>print(type(User)) # <class 'type'> 输出里最后一行最反直觉:u 是 User 的实例,所以 type(u) 是 User;可 User 本身呢?type(User) 居然是 type。 本质一句话...
Redis 主从复制
导言作为分布式系统中实现数据高可用与读写分离的核心技术,Redis 主从复制(Master-Replica Replication)通过多节点数据同步,解决了单点故障风险与读写负载不均问题。 一、核心原理:全量复制与增量复制双机制Redis 主从复制通过 “全量初始化 + 增量衔接” 的方式实现数据同步,两种复制模式适配不同场景需求,需明确触发条件与执行流程。 1. 全量复制:从节点初始化同步触发场景 从节点首次连接主节点(冷启动场景) 从节点断开时间超过repl_backlog_buffer(复制积压缓冲区)大小 主节点执行flushall/flushdb后,从节点同步时无有效偏移量 关键细节 RDB 传输期间主节点通过复制客户端缓冲区(默认 1GB)缓存新写请求,缓冲区满会导致复制失败,需根据写入量调整client-output-buffer-limit replica 从节点加载 RDB 时会阻塞读请求,可通过replica-lazy-flush yes(默认开启)延迟清空数据,减少阻塞时间 2. 增量复制:从节点断连恢复核心依赖 复制偏移量:主从节...
Redis 内存满故障机制
一、Redis 内存分配原理与数据存储特性要解决内存满的问题,首先需理解 Redis 如何占用内存 —— 其内存消耗并非仅用于存储键值对,而是由多模块构成,且数据类型的编码特性直接影响内存效率。 1.1 内存结构组成(按占用比例排序)Redis 的内存消耗主要分为 4 个部分,其中数据区是核心: 数据区(~80%-90%):存储键值对数据,包含键(Key)、值(Value)及数据结构元数据(如哈希表桶、链表节点、跳表索引等)。 例:一个Hash类型键,若采用ziplist编码,会存储字段 / 值的紧凑数组;若转成hashtable,则需额外存储哈希桶、链表指针等元数据,内存占用显著增加。 缓冲区(~5%-15%):包括三类关键缓冲,易被忽视但可能引发内存溢出: 客户端缓冲:每个客户端连接的输入 / 输出缓冲(默认无上限,大量闲置连接会导致缓冲堆积); 复制缓冲:主从同步时的repl-backlog-buffer(默认 1MB,若同步延迟高会扩容); AOF 缓冲:AOF 持久化时的写缓冲(临时存储待写入磁盘的命令)。 进程开销(~...
Python描述符进阶:__get__/__set__协议与属性拦截底层深度解析
一、引言:当你写 obj.x = 1 时,Python 到底做了什么很多 Python 用者以为 obj.x = 1 就是"往对象里塞一个叫 x 的字段"。其实在 C 层面,它走的是 type(obj).__setattr__(obj, 'x', 1),而 __setattr__ 在落盘之前会先去类型上找 x 是不是一个描述符——如果是,就把控制权交给描述符的协议方法。 一句话本质:描述符(descriptor)是 Python 用协议方法(__get__/__set__/__delete__)实现的"属性拦截器",它让"读/写一个属性"变成一次可定制的函数调用;而 C++ 没有语言级的属性拦截,只能靠 getter/setter 约定或元对象编译器(如 Qt 的 moc)来近似。 坑:描述符只认类属性(定义在类型上),定义在实例字典里的同名函数不会触发协议;而且"数据描述符"和"非数据描述符"在查找优先级上完全不同,混用会出...
Redis 作为 MySQL 缓存选择因素归类
引言:高并发时代下的数据库性能困境与缓存破局在现代应用架构中,高并发读取场景(如电商商品详情页、CMS 文章列表、用户会话查询)已成为系统性能的核心挑战。MySQL 作为主流关系型数据库,其 InnoDB 存储引擎基于磁盘 IO 实现数据持久化,在单机并发读场景下,性能通常局限于 1k-10k QPS(受磁盘寻道时间、页缓存命中率影响),难以满足秒杀、大促等峰值需求。 Redis 作为开源高性能内存数据库,凭借 内存级 IO 特性(读 QPS 可达 10 万 - 100 万,写 QPS 可达 5 万 - 50 万)、丰富的数据结构和灵活的过期策略,成为 MySQL 缓存的首选方案。 一、技术原理:Redis 与 MySQL 的协作核心Redis 作为 MySQL 缓存的本质是 “将热点数据从磁盘迁移到内存”,但需解决数据一致性、缓存命中率、异常场景处理三大核心问题。 要点 1:缓存协作模型选型(4 种经典模式)Redis 与 MySQL 的协作需基于业务读写特性选择模型,不同模型的一致性与性能权衡如下: 模型 核心逻辑 适用场景 一致性等级 Cache-Aside 读...
Python asyncio事件循环与协程调度深度解析
一、为什么单线程也能"同时"做很多 IO写爬虫或网关时,常遇到这样的场景:要同时发起上千个网络请求,每个请求大部分时间在等——等 DNS、等 TCP 握手、等对端响应。如果用"一个请求一个线程"的模型,上千线程的上下文切换和内存开销会压垮机器;如果"一个请求一个进程",更不现实。 核心矛盾是:CPU 在等 IO 时其实是闲着的,而线程/进程的切换成本却很高。理想状态是——一个线程在等 A 的回复时,去处理 B、C 的就绪事件,等 A 回来了再回头接着 A 干。 **事件循环(event loop)**就是干这件事的调度器:它在一个线程里维护"谁在等 IO、谁已经就绪、谁该到点执行",按需把控制权交给对应的协程。 本质一句话:事件循环是一个单线程的、基于 IO 多路复用的协作式调度器,靠"协程主动让出"而非"系统抢占"来切换任务。 C++ 对照:C++ 标准库没有内建事件循环。要么自己用 epoll/kqueue/IOCP 手写 ...
通用代码审查清单整理
一、常规功能与可读性(P1+P2) 序号 审查项 判定标准(二元可验证) 优先级 1 功能实现完整性 代码覆盖所有预期需求点(对照需求清单无遗漏,无逻辑错误,如模板特化、重载函数功能符合设计) P1 2 代码易懂性 新接手开发者可在 10 分钟内理解核心逻辑(无过度复杂模板嵌套、晦涩宏定义、无拼音 / 英文混杂命名) P1 3 编码规范符合性 完全匹配团队 C++ 规范(如大括号位置、命名空间使用、const/constexpr正确修饰、缩进无违规) P1 4 冗余代码清理 无重复代码(≥3 行相同逻辑未抽取为函数 / 模板)、无注释掉的无效代码块(如废弃的类成员、未使用的全局函数) P1 5 循环安全性 循环有明确终止条件(无死循环风险),无循环内重计算(如重复获取std::vector长度),无迭代器失效场景(如循环中增删容器元素) P1 6 全局变量 / 对象合理性 无不必要全局变量(可替换为局部变量 / 函数参数),全局对象无初始化顺序依赖风险(如跨文件全局对象相互引用) P2 7 库函数...
Python生成器与协程底层深度解析
一、为什么需要"能暂停"的函数普通函数一旦被调用,就一路执行到 return 或抛异常,然后整个调用栈帧销毁,中间状态全部丢失。这在两种场景下很别扭: 处理大序列不能一次性物化。读一个几十 GB 的日志文件,如果用 readlines() 一把读进内存,内存直接爆。你真正想要的是"读一行、处理一行、扔掉一行"的流式能力。 生产/消费节奏不对等。上游产得快、下游吃得慢,或者反过来,你希望双方各自按自己的节奏走,而不是一方阻塞另一方。 生成器(generator)就是 Python 给出的答案:一个可以暂停、也可以恢复执行的函数。它在 yield 处把值交出来并"冻结"整个调用栈帧,下次再被驱动时从冻结点接着跑。 本质一句话:生成器把"函数的执行"变成了一个可以逐步消费的数据流,暂停时连调用栈一起冻结在堆上。 C++ 对照:在 C++20 之前,语言层面没有协程,要么用回调、要么自己用状态机或栈模拟"可暂停";Python 从 PEP 255(2.2)起就有 yiel...

