下面是一份修复后的版本。主要改动:
- 删除所有失效链接和纯外链引用;
- 将 Python 2 相关内容更新为 Python 3;
- 修正原文中容易误导或错误的表述;
- 代码统一为 Python 3 可运行;
- 保留原文档结构,但做了精简和勘误。
Python 语言特性(Python 3 修复版)#
1. Python 的函数参数传递#
Python 的参数传递既不是“值传递”,也不是“引用传递”,而是 对象引用传递(call by object reference)。
- 变量名只是对象的引用;
- 函数收到的是引用的副本;
- 如果对象不可变(int、str、tuple、frozenset),函数内重新赋值不会影响外部;
- 如果对象可变(list、dict、set),函数内原地修改会影响外部。
a = 1
def fun(a):
a = 2
fun(a)
print(a) # 1
a = []
def fun(a):
a.append(1)
fun(a)
print(a) # [1]用 id 观察:
a = 1
def fun(a):
print("func_in", id(a))
a = 2
print("re-point", id(a), id(2))
print("func_out", id(a), id(1))
fun(a)
print(a) # 1不可变对象重新赋值后,引用指向新对象;可变对象原地修改时,引用不变。
2. Python 中的元类(metaclass)#
元类是“创建类的类”。默认情况下,type 就是所有类的元类。元类常用于 ORM、框架等需要控制类创建过程的场景。日常业务开发很少直接使用。
3. @staticmethod 和 @classmethod#
Python 中有三种方法:
- 实例方法:第一个参数是
self,通过实例调用; - 类方法:第一个参数是
cls,通过类或实例调用; - 静态方法:没有默认第一个参数,通过类或实例调用,本质上就是普通函数。
class A:
def foo(self, x):
print(f"executing foo({self}, {x})")
@classmethod
def class_foo(cls, x):
print(f"executing class_foo({cls}, {x})")
@staticmethod
def static_foo(x):
print(f"executing static_foo({x})")
a = A()
a.foo(1)
a.class_foo(1)
A.class_foo(1)
a.static_foo(1)
A.static_foo(1)4. 类变量和实例变量#
- 类变量:在类中定义,所有实例共享;
- 实例变量:在
__init__中用self.xxx定义,每个实例独立。
class Test:
num_of_instance = 0
def __init__(self, name):
self.name = name
Test.num_of_instance += 1
print(Test.num_of_instance) # 0
t1 = Test('jack')
print(Test.num_of_instance) # 1
t2 = Test('lucy')
print(t1.name, t1.num_of_instance) # jack 2
print(t2.name, t2.num_of_instance) # lucy 2注意:如果类变量是可变对象,所有实例共享它,容易出问题。
class Person:
name = []
p1 = Person()
p2 = Person()
p1.name.append(1)
print(p1.name) # [1]
print(p2.name) # [1]
print(Person.name) # [1]5. Python 自省#
自省指运行时获取对象信息。常用函数:
type()dir()getattr()hasattr()isinstance()
a = [1, 2, 3]
b = {'a': 1, 'b': 2, 'c': 3}
c = True
print(type(a), type(b), type(c))
print(isinstance(a, list)) # True6. 字典推导式#
d = {key: value for key, value in iterable.items()}7. 单下划线和双下划线#
__foo__:Python 内部特殊方法,如__init__、__del__;_foo:约定私有,from module import *不会导入;__foo:名称改写(name mangling),解析器会变成_类名__foo。
class MyClass:
def __init__(self):
self.__superprivate = "Hello"
self._semiprivate = ", world!"
mc = MyClass()
# print(mc.__superprivate) # AttributeError
print(mc._semiprivate) # , world!
print(mc.__dict__) # {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
print(mc._MyClass__superprivate) # Hello8. 字符串格式化#
Python 3 推荐使用 f-string,其次 str.format(),% 仍可用但不推荐。
name = "小明"
age = 20
print(f"{name}的年龄是{age}岁!")% 的问题:如果变量是元组,需要写成 "hi there %s" % (name,)。
9. 迭代器和生成器#
列表生成式用 [],生成器表达式用 ()。
L = [x * x for x in range(10)]
g = (x * x for x in range(10))
print(L) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
print(g) # <generator object ...>生成器边循环边计算,节省内存。yield 用于创建生成器。
10. *args 和 **kwargs#
*args:接收任意数量的位置参数,打包为元组;**kwargs:接收任意数量的关键字参数,打包为字典。
def print_everything(*args):
for count, thing in enumerate(args):
print(f'{count}. {thing}')
def table_things(**kwargs):
for name, value in kwargs.items():
print(f'{name} = {value}')
print_everything('apple', 'banana', 'cabbage')
table_things(apple='fruit', cabbage='vegetable')调用时也可以用 * 和 ** 解包。
11. 面向切面编程 AOP 和装饰器#
装饰器用于在不修改原函数代码的情况下增加功能,如日志、性能测试、事务处理。
import time
def count_time(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"耗时 {end - start:.4f}s")
return result
return wrapper
@count_time
def work():
time.sleep(0.5)
work()12. 鸭子类型#
“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。”
Python 不关心对象的具体类型,只关心它是否具有所需的方法或行为。
class Duck:
def quack(self):
print("quack")
class Person:
def quack(self):
print("I can quack too")
def make_quack(obj):
obj.quack()
make_quack(Duck())
make_quack(Person())13. Python 中重载#
Python 不支持传统函数重载。因为 Python 可以接受任意类型参数,也可以用默认参数、可变参数处理不同参数个数。
如果需要按类型分派,可以用 functools.singledispatch。
14. 新式类和旧式类#
Python 3 中所有类都是新式类,默认继承 object。旧式类只存在于 Python 2。新式类使用 C3 算法计算 MRO。
15. new 和 init 的区别#
__new__:静态方法,创建并返回实例;__init__:实例方法,初始化实例,无返回值;- 只有
__new__返回当前类实例时,才会调用__init__。
16. 单例模式#
方法一:使用 new#
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
class MyClass(Singleton):
a = 1方法二:装饰器#
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class MyClass:
pass方法三:模块天然单例#
Python 模块只会被导入一次,因此模块级变量天然是单例。
17. Python 中的作用域#
变量搜索顺序为 LEGB:
- Local:本地作用域
- Enclosing:嵌套函数的外层作用域
- Global:全局/模块作用域
- Built-in:内置作用域
18. GIL 线程全局锁#
GIL 是 CPython 解释器中的全局锁,保证同一进程内同一时刻只有一个线程执行 Python 字节码。
- 对 I/O 密集型任务,多线程仍有效;
- 对 CPU 密集型任务,多线程无法利用多核,建议用多进程或
concurrent.futures。
19. 协程#
协程是用户态轻量级线程,由程序自己控制切换,减少内核态切换开销。Python 3 中推荐使用 async / await。
import asyncio
async def hello():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(hello())生成器也可以实现协程,但现代写法是 async / await。
20. 闭包#
闭包条件:
- 有内嵌函数;
- 内嵌函数引用外部函数的变量;
- 外部函数返回内嵌函数。
def outer(x):
def inner(y):
return x + y
return inner
f = outer(10)
print(f(5)) # 15闭包会让外部函数的变量在函数返回后继续存在。
21. lambda 函数#
匿名函数。
f = lambda x: x * x
print(f(4)) # 16
g = lambda x, y: x + y
print(g(1, 2)) # 322. Python 函数式编程#
filter(function, iterable):过滤;map(function, iterable):映射;reduce(function, iterable):在functools中,归约。
from functools import reduce
a = [1, 2, 3, 4, 5, 6, 7]
b = filter(lambda x: x > 5, a)
print(list(b)) # [6, 7]
c = map(lambda x: x * 2, [1, 2, 3])
print(list(c)) # [2, 4, 6]
print(reduce(lambda x, y: x * y, range(1, 4))) # 623. Python 里的拷贝#
- 赋值:传递对象引用;
- 浅拷贝:创建新对象,但内部嵌套对象仍共享引用;
- 深拷贝:递归复制所有层级,完全独立。
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')
print('a =', a)
print('b =', b)
print('c =', c)
print('d =', d)输出:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]24. Python 垃圾回收机制#
Python GC 主要使用:
- 引用计数:对象引用数为 0 时立即回收;
- 标记-清除:解决循环引用;
- 分代回收:将对象分为三代,越老的对象回收频率越低。
优点:实时性、简单;缺点:维护引用计数有开销,循环引用需要额外机制。
25. Python 的 List#
Python 列表是动态数组,支持随机访问、尾部追加高效,头部插入/删除较慢。底层是连续内存,扩容时按一定比例增长。
26. Python 的 is#
is:比较内存地址,即是否是同一个对象;==:比较值是否相等。
27. read、readline 和 readlines#
read():读取整个文件;readline():读取下一行;readlines():读取所有行,返回列表。
28. Python 2 和 3 的区别#
print变成函数;- 字符串默认 Unicode;
range返回惰性序列,xrange被移除;- 除法
/返回浮点数,整除用//; - 异常语法
except Exception as e; - 字典
keys()、values()、items()返回视图; - 推荐使用 f-string。
29. super init#
Python 3 中推荐:
class Child(Base):
def __init__(self):
super().__init__()30. range 和 xrange#
Python 3 中只有 range,它返回惰性序列,类似 Python 2 的 xrange。xrange 已移除。
操作系统#
1. select、poll 和 epoll#
I/O 多路复用机制:
select:连接数受限,查找慢,有内核到用户态拷贝;poll:改进了连接数限制;epoll:Linux 下更高效,支持边沿触发和水平触发。
2. 调度算法#
- 先来先服务 FCFS
- 短作业优先 SJF
- 最高优先权调度
- 时间片轮转 RR
- 多级反馈队列
实时调度:EDF、LLF。
3. 死锁#
必要条件:
- 互斥;
- 请求和保持;
- 不可剥夺;
- 循环等待。
处理方式:预防、避免(银行家算法)、检测、解除。
4. 程序编译与链接#
过程:
- 预处理:展开宏、包含头文件、删除注释;
- 编译:词法、语法、语义分析,生成汇编;
- 汇编:生成目标文件;
- 链接:地址分配、符号决议、重定位。
5. 静态链接和动态链接#
- 静态链接:程序启动前确定地址,运行性能好,体积大;
- 动态链接:运行时加载,初始化快,运行性能略低,节省空间。
6. 虚拟内存技术#
虚拟内存让程序可以使用比物理内存更大的地址空间,具有请求调入和置换功能。
7. 分页和分段#
- 分页:固定大小,物理单位,一维地址;
- 分段:可变大小,逻辑单位,二维地址。
8. 页面置换算法#
- OPT:最佳置换,理论最优;
- FIFO:先进先出;
- LRU:最近最久未使用;
- Clock:时钟算法。
9. 边沿触发和水平触发#
- 边沿触发:状态变化时通知一次;
- 水平触发:只要就绪就通知。
数据库#
1. 事务#
事务是一组要么全部成功、要么全部失败的操作。ACID:原子性、一致性、隔离性、持久性。
2. 数据库索引#
索引用于加速查询。常见结构:B+Tree、Hash。InnoDB 使用聚簇索引,MyISAM 使用非聚簇索引。最左前缀原则适用于联合索引。
3. Redis 原理#
Redis 是内存 key-value 数据库,支持字符串、哈希、列表、集合、有序集合等。特点:速度快、支持持久化、主从复制、分片。缺点:容量受内存限制,在线扩容复杂。
4. 乐观锁和悲观锁#
- 悲观锁:假设会冲突,先加锁;
- 乐观锁:假设不会冲突,提交时检查版本。
5. MVCC#
多版本并发控制。InnoDB 每行有创建版本和删除版本。读操作读取符合版本的快照,实现非阻塞读。写操作递增版本号,旧数据由 purge 线程清理。
6. MyISAM 和 InnoDB#
- MyISAM:表锁,读多写少,
COUNT(*)快,不支持事务; - InnoDB:行锁,支持事务、外键,写并发更好。
网络#
1. 三次握手#
- 客户端发送 SYN;
- 服务器回复 SYN+ACK;
- 客户端发送 ACK。
2. 四次挥手#
- 主动关闭方发送 FIN;
- 被动方回复 ACK;
- 被动方发送 FIN;
- 主动方回复 ACK,进入 TIME_WAIT,等待 2MSL。
3. ARP 协议#
根据 IP 地址查询 MAC 地址。IPv6 中使用 NDP。
4. urllib 和 urllib2 的区别#
这是 Python 2 的概念。Python 3 中统一为 urllib.request、urllib.parse、urllib.error。
5. Post 和 Get#
- GET:获取资源,参数在 URL,幂等;
- POST:提交数据,参数在请求体,非幂等。
6. Cookie 和 Session#
- Cookie 存客户端,不安全;
- Session 存服务器端,通常依赖 Cookie 保存 Session ID。
7. Apache 和 Nginx 的区别#
- Nginx:轻量、异步非阻塞、高并发、配置简洁;
- Apache:模块多、rewrite 强大、稳定,但高并发下资源消耗较高。
8. 网站用户密码保存#
推荐使用 bcrypt、argon2 等加盐哈希,不要明文保存,也不要只用 MD5。
9. HTTP 和 HTTPS#
状态码:
- 1xx 信息
- 2xx 成功
- 3xx 重定向
- 4xx 客户端错误
- 5xx 服务器错误
HTTPS 使用 TLS/SSL,结合对称加密和非对称加密。
10. XSRF 和 XSS#
- CSRF:跨站请求伪造,重点在请求;
- XSS:跨站脚本攻击,重点在脚本。
11. 幂等#
幂等指一次和多次请求产生相同副作用。GET、PUT、DELETE 通常幂等,POST 不幂等。
12. RESTful 架构#
以资源为中心,使用 HTTP 方法表达操作。RPC -> SOAP -> RESTful 是常见演进路径。
13. SOAP#
基于 XML 的 Web 服务协议,较重。
14. RPC#
远程过程调用,像调用本地函数一样调用远程服务。
15. CGI 和 WSGI#
- CGI:通用网关接口;
- WSGI:Python Web 服务器和应用程序之间的接口规范。
16. 中间人攻击#
攻击者在通信两端之间分别建立连接,窃取或篡改数据。
17. c10k 问题#
服务器同时支持上万个连接的问题。解决思路:I/O 多路复用、异步、协程等。
18. socket#
Socket = IP 地址 + 协议 + 端口。
19. 浏览器缓存#
通过 Cache-Control、ETag、Last-Modified 等控制。304 Not Modified 表示缓存有效。
20. HTTP 1.0 和 HTTP 1.1#
HTTP/1.1 引入:
- Host 头;
- 长连接;
- 断点续传;
- 缓存和身份认证改进。
HTTP 方法:GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH。
21. Ajax#
异步 JavaScript 和 XML,用于不刷新页面更新部分内容。现代常用 Fetch API 或 Axios。
*NIX#
下面是在上一版基础上,为每种 IPC 方式补充了更具体的使用场景的完整版本。你可以直接替换原文档中的“Unix 进程间通信方式(IPC)”一节。
Unix 进程间通信方式(IPC)#
进程间通信(Inter-Process Communication,IPC)指不同进程之间交换数据或同步动作的机制。Unix/Linux 提供了多种 IPC 方式,按用途大致可分为三类:
- 数据传输类:管道、命名管道、消息队列、套接字;
- 共享存储类:共享内存、内存映射;
- 同步控制类:信号、信号量。 下面逐一说明
1. 管道(Pipe)#
- 定义:匿名管道,由
pipe()创建,返回两个文件描述符:一个读端、一个写端。 - 特点:
- 半双工,数据只能单向流动;
- 只能用于具有亲缘关系的进程(父子、兄弟);
- 基于字节流,没有消息边界;
- 生命周期随进程,进程退出后自动消失;
- 读写默认阻塞,缓冲区满时写阻塞,空时读阻塞。
- 系统调用:
pipe()、pipe2()。
典型使用场景:
- Shell 命令管道:
ls | grep .py、ps aux | sort -k 3 -nr | head。 - 父子进程协作:父进程写数据,子进程读数据并处理。
- 简单日志传递:一个进程产生日志,另一个进程负责写入文件。
- 数据处理流水线:多个进程串行处理同一批数据。
int fd[2];
pipe(fd);
if (fork() == 0) {
close(fd[0]);
write(fd[1], "hello", 5);
} else {
close(fd[1]);
char buf[10];
read(fd[0], buf, 5);
}2. 命名管道(Named Pipe / FIFO)#
- 定义:有名字的管道,在文件系统中表现为特殊文件,通过
mkfifo()创建。 - 特点:
- 克服匿名管道只能用于亲缘进程的限制;
- 无关进程也可通过打开同一个 FIFO 文件通信;
- 仍然是半双工、字节流;
- 打开 FIFO 时通常会阻塞,直到另一端也被打开。
- 系统调用:
mkfifo()、open()、read()、write()。
典型使用场景:
- 不相关进程间通信:如监控进程和日志进程。
- 简单的客户端-服务器模型:客户端写请求,服务器读请求。
- Shell 脚本间传递数据:
mkfifo /tmp/f; echo "data" > /tmp/f & cat /tmp/f。 - 替代临时文件:避免磁盘 I/O,提高效率。
mkfifo /tmp/myfifo
echo "hello" > /tmp/myfifo &
cat /tmp/myfifo3. 信号(Signal)#
- 定义:异步通知机制,用于通知进程发生了某个事件。
- 特点:
- 信息量极少,通常只传信号编号;
- 不携带数据,只表示“某事发生”;
- 可靠信号(实时信号)支持排队,不可靠信号可能丢失;
- 进程可选择忽略、捕获或使用默认处理。
- 常用信号:
SIGINT、SIGTERM、SIGKILL、SIGUSR1、SIGUSR2。 - 系统调用:
kill()、raise()、signal()、sigaction()、sigqueue()。
典型使用场景:
- 终止/中断进程:
Ctrl+C发送SIGINT,kill -9发送SIGKILL。 - 配置热重载:如 nginx 收到
SIGHUP后重新加载配置。 - 父子进程通知:子进程退出时向父进程发送
SIGCHLD。 - 自定义事件:进程间用
SIGUSR1、SIGUSR2传递简单通知。 - 超时/定时提醒:
alarm()触发SIGALRM。
void handler(int sig) {
printf("received signal %d\n", sig);
}
signal(SIGUSR1, handler);
kill(getpid(), SIGUSR1);4. 消息队列(Message Queue)#
- 定义:内核维护的消息链表,进程可发送和接收消息。
- 特点:
- 有消息边界,按类型或优先级读取;
- 支持多进程读写;
- 生命周期随内核,除非显式删除或系统重启;
- 分为 System V 和 POSIX 两种。
- System V 系统调用:
msgget()、msgsnd()、msgrcv()、msgctl()。 - POSIX 接口:
mq_open()、mq_send()、mq_receive()、mq_close()、mq_unlink()。
典型使用场景:
- 异步任务分发:生产者投递任务,多个消费者按类型领取。
- 多进程日志收集:各进程写入同一消息队列,日志进程统一处理。
- 模块解耦:不同模块通过消息队列通信,避免直接依赖。
- 优先级消息:紧急消息优先处理,如告警系统。
// System V 示例
int msqid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
msgsnd(msqid, &msg, size, 0);
msgrcv(msqid, &msg, size, type, 0);5. 共享内存(Shared Memory)#
- 定义:多个进程将同一块物理内存映射到各自地址空间,直接读写。
- 特点:
- 最快的 IPC 方式,无需用户态和内核态之间的数据拷贝;
- 需配合同步机制(信号量、互斥锁)防止竞态;
- 生命周期随内核,需显式删除;
- 分为 System V 和 POSIX 共享内存。
- System V 系统调用:
shmget()、shmat()、shmdt()、shmctl()。 - POSIX 接口:
shm_open()、mmap()、munmap()、shm_unlink()。
典型使用场景:
- 高性能数据交换:实时系统、金融交易、游戏服务器。
- 大规模共享缓存:多个进程共享同一份数据,避免重复加载。
- 数据库缓冲区:PostgreSQL、Redis 等使用共享内存做缓存。
- 视频/图像处理:多进程共享帧数据,减少拷贝开销。
- 科学计算:并行计算中共享中间结果。
int shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
void *ptr = shmat(shmid, NULL, 0);
strcpy(ptr, "hello");
shmdt(ptr);6. 内存映射(Memory-mapped I/O / mmap)#
- 定义:将文件或匿名内存区域映射到进程地址空间,进程可像访问内存一样访问文件。
- 特点:
- 可用于文件映射和匿名映射;
- 匿名映射可用于亲缘进程间共享内存;
- 文件映射可用于无关进程通过同一文件共享数据;
- 支持写时复制(COW);
- 常与
mmap()、munmap()、msync()配合。
- 系统调用:
mmap()、munmap()、msync()。
典型使用场景:
- 大文件读写:避免
read/write的系统调用开销,如数据库、日志系统。 - 动态库加载:操作系统加载
.so文件时使用mmap。 - 进程间共享内存:
MAP_SHARED | MAP_ANONYMOUS实现父子进程共享。 - 内存映射文件:多个进程映射同一文件,实现数据共享。
- 零拷贝 I/O:网络传输、文件服务器中减少数据拷贝。
int fd = open("file", O_RDWR);
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);7. 信号量(Semaphore)#
- 定义:用于进程间或线程间同步的计数器,常用于保护共享资源。
- 特点:
- 本身不传递数据,只用于同步和互斥;
- 分为 System V 和 POSIX 信号量;
- POSIX 信号量又分命名和匿名;
- 支持 P 操作(wait)和 V 操作(post)。
- System V 系统调用:
semget()、semop()、semctl()。 - POSIX 接口:
sem_init()、sem_wait()、sem_post()、sem_destroy()、sem_open()。
典型使用场景:
- 保护共享内存:多个进程访问同一块共享内存时,用信号量互斥。
- 生产者-消费者模型:缓冲区满/空时通过信号量阻塞和唤醒。
- 资源计数:限制同时访问某资源的进程数量,如连接池、线程池。
- 读写锁:通过信号量实现读写优先级控制。
- 进程同步:确保多个进程按特定顺序执行。
sem_t sem;
sem_init(&sem, 1, 1);
sem_wait(&sem);
// 临界区
sem_post(&sem);
sem_destroy(&sem);8. 套接字(Socket)#
- 定义:通用的网络通信接口,也可用于本机进程间通信。
- 特点:
- 支持全双工通信;
- 可用于不同主机之间的进程通信;
- Unix 域套接字(
AF_UNIX)用于本机,性能高于 TCP/IP; - 支持流式(
SOCK_STREAM)和数据报(SOCK_DGRAM); - Unix 域套接字可传递文件描述符。
- 系统调用:
socket()、bind()、listen()、accept()、connect()、send()、recv()。
典型使用场景:
- 网络服务:Web 服务器、数据库、消息队列等。
- 本机高性能 IPC:Docker、systemd、X11 使用 Unix 域套接字。
- 跨主机通信:微服务、分布式系统、RPC。
- 文件描述符传递:Unix 域套接字可在进程间传递打开的 fd。
- 实时通信:游戏、聊天、推送服务。
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, "/tmp/mysock");
bind(sock, (struct sockaddr*)&addr, sizeof(addr));IPC 方式对比#
| 方式 | 是否跨主机 | 是否亲缘限制 | 数据边界 | 速度 | 典型用途 |
|---|---|---|---|---|---|
| 管道 | 否 | 是 | 字节流 | 中 | 父子进程简单通信 |
| 命名管道 | 否 | 否 | 字节流 | 中 | 无关进程简单通信 |
| 信号 | 否 | 否 | 无 | 快 | 事件通知 |
| 消息队列 | 否 | 否 | 有 | 中 | 结构化消息 |
| 共享内存 | 否 | 否 | 无 | 最快 | 高性能数据共享 |
| 内存映射 | 否 | 否 | 无 | 快 | 文件共享、大内存 |
| 信号量 | 否 | 否 | 无 | 快 | 同步互斥 |
| 套接字 | 是 | 否 | 流/报文 | 中 | 网络、本机通用 |
如何选择 IPC 方式#
- 只需要通知事件:用信号。
- 父子进程简单传数据:用管道。
- 无关进程简单传数据:用命名管道。
- 需要结构化消息、异步处理:用消息队列。
- 追求极致性能、大数据共享:用共享内存 + 信号量。
- 需要文件共享、零拷贝:用内存映射。
- 需要跨主机通信:用套接字。
- 本机高性能、全双工:用 Unix 域套接字。
补充:现代 Linux 新增的 IPC 机制#
除了传统方式,Linux 还提供了一些更轻量、更高效的 IPC 机制:
- eventfd:用于事件通知,常与 epoll 配合;
- signalfd:将信号转换为文件描述符,便于统一事件循环;
- timerfd:定时器通知;
- memfd_create:创建匿名内存文件,可用于进程间共享内存;
- io_uring:高性能异步 I/O 接口,也可用于进程间通信。
这些机制在高性能服务器、容器、微服务中越来越常见。
数据结构#
红黑树#
红黑树是非严格平衡二叉搜索树,增删旋转次数比 AVL 少。搜索多、增删少用 AVL;搜索和增删均衡用红黑树。
编程题#
1. 台阶问题 / 斐波那契#
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return b2. 变态台阶问题#
def fib(n):
return n if n < 2 else 2 * fib(n - 1)3. 矩形覆盖#
def cover(n):
return 1 if n < 2 else cover(n - 1) + cover(n - 2)4. 杨氏矩阵查找#
def find(matrix, target):
if not matrix:
return False
rows, cols = len(matrix), len(matrix[0])
r, c = 0, cols - 1
while r < rows and c >= 0:
val = matrix[r][c]
if val == target:
return True
elif val > target:
c -= 1
else:
r += 1
return False5. 去除列表中的重复元素#
def dedup(lst):
return list(dict.fromkeys(lst))6. 链表成对调换#
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def swap_pairs(head):
if head and head.next:
nxt = head.next
head.next = swap_pairs(nxt.next)
nxt.next = head
return nxt
return head7. 创建字典的方法#
d1 = {'name': 'earth', 'port': '80'}
d2 = dict([('name', 'earth'), ('port', '80')])
d3 = dict.fromkeys(('x', 'y'), -1)8. 合并两个有序列表#
def merge_sorted(a, b):
res = []
i = j = 0
while i < len(a) and j < len(b):
if a[i] <= b[j]:
res.append(a[i])
i += 1
else:
res.append(b[j])
j += 1
res.extend(a[i:])
res.extend(b[j:])
return res9. 交叉链表求交点#
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def get_intersection(headA, headB):
if not headA or not headB:
return None
pA, pB = headA, headB
while pA != pB:
pA = pA.next if pA else headB
pB = pB.next if pB else headA
return pA10. 二分查找#
def binary_search(nums, target):
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
low = mid + 1
else:
high = mid - 1
return -111. 快排#
def quicksort(nums):
if len(nums) < 2:
return nums
pivot = nums[0]
less = [x for x in nums[1:] if x <= pivot]
greater = [x for x in nums[1:] if x > pivot]
return quicksort(less) + [pivot] + quicksort(greater)12. 找零问题#
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -113. 广度遍历和深度遍历二叉树#
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def bfs(root):
if not root:
return
queue = [root]
while queue:
node = queue.pop(0)
print(node.data)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
def dfs(root):
if not root:
return
print(root.data)
dfs(root.left)
dfs(root.right)14. 前中后序遍历#
def preorder(root):
if root:
print(root.data)
preorder(root.left)
preorder(root.right)
def inorder(root):
if root:
inorder(root.left)
print(root.data)
inorder(root.right)
def postorder(root):
if root:
postorder(root.left)
postorder(root.right)
print(root.data)15. 求最大树深#
def max_depth(root):
if not root:
return 0
return max(max_depth(root.left), max_depth(root.right)) + 116. 求两棵树是否相同#
def is_same_tree(p, q):
if not p and not q:
return True
if not p or not q:
return False
return p.val == q.val and is_same_tree(p.left, q.left) and is_same_tree(p.right, q.right)17. 前序中序求后序#
def rebuild(pre, inorder):
if not pre:
return None
root = Node(pre[0])
idx = inorder.index(pre[0])
root.left = rebuild(pre[1:idx + 1], inorder[:idx])
root.right = rebuild(pre[idx + 1:], inorder[idx + 1:])
return root
def postorder(root):
if not root:
return
postorder(root.left)
postorder(root.right)
print(root.data)18. 单链表逆置#
def reverse_list(head):
prev = None
cur = head
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
return prev19. 两个字符串是否是变位词#
from collections import Counter
def is_anagram(s1, s2):
return Counter(s1) == Counter(s2)20. 动态规划#
动态规划适用于有重叠子问题和最优子结构的问题。步骤:
- 定义状态;
- 找状态转移方程;
- 初始化;
- 确定遍历顺序;
- 返回结果。
常见题:背包、最长公共子序列、最长递增子序列、编辑距离等。