I/O多路复用
I/O 多路复用(I/O Multiplexing)是一种在计算机网络编程中至关重要的技术,也是构建高性能服务器的基石。 1. 背景:为什么需要 I/O 多路复用?想象一下你要开发一个网络服务器,需要同时处理多个客户端的连接。我们来看看几种最原始的模型以及它们的缺陷。 模型一:阻塞 I/O + 多进程/多线程这是最直观的模型。主进程负责监听(listen)新的连接请求。每当有一个新的客户端连接进来(accept),服务器就创建一个新的进程或线程专门为这个客户端服务。 工作流程: 主线程/进程 accept() 等待新连接,阻塞。 新连接到达,accept() 返回一个新的socket文件描述符(fd)。 创建一个子线程/进程,将这个新的fd交给它处理。 子线程/进程在这个fd上调用 read()/recv(),等待客户端发送数据,阻塞。 数据到达,read() 返回,处理数据,然后可能调用...
零拷贝
摘要:什么是零拷贝?零拷贝(Zero-Copy) 并不是指完全没有数据拷贝,而是指尽可能地减少或避免在应用程序的用户空间(User Space)和操作系统的内核空间(Kernel Space)之间进行不必要的CPU数据拷贝。其核心目标是让数据在从一个I/O设备(如硬盘)到另一个I/O设备(如网卡)的传输过程中,最大限度地利用硬件(如DMA)来搬运数据,从而解放CPU,减少上下文切换,显著提升数据传输的性能和效率。 一、 理解背景:传统I/O的痛点要理解零拷贝的价值,我们必须先了解传统的数据传输方式有多么“昂贵”。 假设我们要实现一个简单的文件服务器,其功能是:从磁盘读取一个文件,然后通过网络发送给客户端。 传统I/O的操作流程: 我们用代码来看,通常是这样的: 12read(file_fd, buffer, len);write(socket_fd, buffer, len); 这个看似简单的两行代码,在操作系统层面会触发一系列复杂的步骤: 第一次拷贝(DMA Copy): 应用程序调用 read()...
正则表达式与模式匹配
第一部分:正则表达式(Regular Expression)详解1. 什么是正则表达式?正则表达式是一种描述字符模式的对象。可以把它想象成一种极其强大的“查找和替换”工具,它不是用固定的字符(如 “abc”)去查找,而是用一种描述性的语言(如 “查找三个数字”)去匹配一系列符合某个句法规则的字符串。 它的核心用途包括: 数据验证:检查输入的数据是否符合某种格式(如邮箱、手机号、身份证号)。 文本搜索与定位:在大量文本中快速找到符合特定模式的内容。 文本提取:从一段文本中抽取出需要的信息(如网页爬虫中提取标题和链接)。 文本替换:将符合模式的文本替换成其他内容。 2. 核心组成元素(元字符 Metacharacters)正则表达式的威力来自于它的特殊字符——元字符。普通字符(如 a, b, 1, 2)在正则中就是匹配它们自身,而元字符则有特殊的含义。 2.1 基础字符与预定义字符集 元字符 描述 示例 . 匹配除换行符 \n 之外的任意单个字符 a.c 匹配 “abc”, “a_c”, “a2c” \d 匹配任意一个数字(等价于 [0-9]) \d{3} 匹配...
CPP学习笔记—依赖注入
依赖注入 (Dependency Injection, DI)。这是一个在现代软件工程中至关重要的概念,尤其是在构建大型、可维护和可测试的系统中。 1. 什么是依赖?什么是问题所在?在面向对象编程中,一个类(或对象)通常需要依赖其他类(或对象)来完成其工作。这种“需要”就是依赖。 问题代码(紧密耦合): 让我们从一个没有使用依赖注入的例子开始。假设我们有一个 Car 类,它需要一个 Engine 和一个 Logger 来工作。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546#include <iostream>#include <string>// 依赖 1: 具体的 V8 引擎class V8Engine {public: void start() { std::cout << "V8 Engine starts. Vroom Vroom!" <<...
CPP学习笔记—工厂模式
1. 什么是工厂模式?为什么需要它?核心思想:工厂模式是一种创建型设计模式,其核心思想是将对象的创建过程封装起来。客户端(使用对象的代码)不再直接使用 new 关键字来创建具体类的实例,而是向一个“工厂”请求一个对象,由工厂来决定到底创建哪个具体类的实例。 解决的问题:想象一下,如果没有工厂模式,你的代码可能会是这样的: 12345678910111213141516// 客户端代码void some_function(const std::string& shapeType) { Shape* shape = nullptr; if (shapeType == "Circle") { shape = new Circle(); // 直接依赖具体类 Circle } else if (shapeType == "Square") { shape = new Square(); // 直接依赖具体类 Square } else...
CPP学习笔记—单例模式
1. 什么是单例模式?单例模式是一种创建型设计模式,其核心思想是确保一个类在任何情况下都只有一个实例,并提供一个全局访问点来获取这个唯一的实例。 可以把它想象成一个国家的总统或者一个学校的校长,在整个系统运行期间,这个角色只能有一个人担任。无论你从哪个部门、哪个流程去“找校长”,最终找到的都是同一个人。 为了在 C++ 中实现这一点,通常需要满足三个关键条件: 私有的构造函数:为了防止外部代码通过 new 操作符随意创建类的实例。 一个私有的、静态的、指向本类实例的指针或对象:这是存放那个唯一实例的地方。 一个公有的、静态的、用于获取实例的方法:这是全局唯一的访问点,负责创建并返回那个唯一的实例。 2. 为什么需要单例模式?单例模式主要用于解决那些“全局唯一”且需要被频繁共享访问的资源或服务。常见的应用场景包括: 日志记录器(Logger):整个应用程序通常只需要一个日志记录器,所有模块都通过它来写入日志文件。 配置管理器(Configuration Manager):读取和管理应用的配置信息(如数据库连接字符串、API...
CPP学习笔记—初始化方式
C++ 的初始化是一个庞大而精细的主题,从 C 语言的简单赋值风格,到 C++11 引入的统一初始化,其发展历程旨在解决二义性、提高类型安全性和代码一致性。 为什么初始化如此重要?在 C++ 中,一个未经初始化的变量(非静态局部变量)拥有一个不确定的值。读取这个值会导致未定义行为 (Undefined Behavior, UB),这是 C++ 中最危险的陷阱之一,可能导致程序崩溃、数据损坏或看似正常运行但结果错误。 C++ 初始化方式的演变与分类我们可以大致将初始化方式分为两大类:C++11 之前的传统方式和 C++11 及其之后引入的统一初始化(大括号初始化)。 第一部分:C++11 之前的传统初始化方式在 C++11 之前,主要有以下几种初始化方式,它们的语法不统一,有时会带来困惑。 1. 默认初始化 (Default Initialization)当一个变量在定义时没有提供显式的初始值时,就会发生默认初始化。 语法: 1T object_name; 行为: 对于局部变量(在函数内定义):如果 T 是内置类型(如 int, double,...
CPP学习笔记—priority_queue
1. priority_queue 是什么?std::priority_queue 是 C++ 标准模板库(STL)中的一个容器适配器,它提供了一种特殊的队列:优先级队列。 核心概念:优先出队与普通的队列(std::queue)遵循“先进先出”(FIFO)的原则不同,优先级队列中的元素并非根据其进入队列的顺序出队,而是根据其优先级。每次从队列中取出的元素(通过 top() 访问,pop() 移除),都是当前队列中优先级最高的那个。 默认情况下,对于数字,“大”的元素优先级更高;对于其他类型,使用 std::less 作为比较函数,即通过 operator< 来判断优先级。 底层数据结构:堆 (Heap)priority_queue 的高效实现得益于其底层的堆数据结构。通常是最大堆 (Max-Heap)。 堆:一个特殊的完全二叉树,满足“堆属性”:父节点的值总是大于或等于(最大堆)或小于或等于(最小堆)其所有子节点的值。 最大堆 (Max-Heap):根节点是整个堆中最大的元素。std::priority_queue 默认就是最大堆。 最小堆...
CPP学习笔记—unordered_map
1. unordered_map 是什么?std::unordered_map 是 C++ 标准模板库(STL)中的一个关联容器,它存储了由“键(Key)”和“值(Value)”组成的元素对(std::pair<const Key, Value>)。它的核心特点是: 无序性:元素在容器内的存储顺序是无序的,遍历 unordered_map 时,得到的元素顺序与插入顺序无关,并且在不同编译环境下可能不同。 基于哈希表:其内部实现是一个哈希表(Hash Table)。 高效查询:由于使用了哈希表,它提供了非常快的平均时间复杂度的操作: 插入、删除、查找:平均 O(1) 最坏情况:O(N),其中 N 是容器中元素的数量(当发生严重的哈希冲突时)。 核心概念:哈希表为了理解 unordered_map,需要了解哈希表的工作原理: 哈希函数 (Hash Function):当插入一个键值对时,unordered_map 会使用一个哈希函数将“键”转换成一个整数,这个整数被称为哈希值(Hash Code)。 桶 (Bucket):unordered_map...
算法模板
拓扑排序1234567891011121314151617181920212223# 返回有向无环图(DAG)的其中一个拓扑序# 如果图中有环,返回空列表# 节点编号从 0 到 n-1def topologicalSort(n: int, edges: List[List[int]]) -> List[int]: g = [[] for _ in range(n)] in_deg = [0] * n for x, y in edges: g[x].append(y) in_deg[y] += 1 # 统计 y 的先修课数量 topo_order = [] q = deque(i for i, d in enumerate(in_deg) if d == 0) # 没有先修课,可以直接上 while q: x = q.popleft() topo_order.append(x) for y in g[x]: in_deg[y] -= 1 #...












