知识点
GIL(全局解释器锁)
GIL 是 Python(CPython)解释器中的全局解释器锁,确保同一时间只有一个线程可以执行 Python 字节码。
影响:
- 多线程(
threading模块)在 CPU 密集型任务(如数学计算)中受限,不能并行地利用多核 CPU - 对于 I/O 密集型任务(如文件操作、网络请求等),多线程仍然可以提高效率,因为在 I/O 操作时线程会释放 GIL
解决方法:
- 使用
multiprocessing模块来创建多个进程,以实现真正的并行 - 使用 GIL 之外的扩展模块,如
NumPy或某些 C 扩展,它们可以绕过 GIL
迭代器和生成器
迭代器
实现了 __iter__() 和 __next__() 方法的对象,支持逐个返回元素,直到元素耗尽时抛出 StopIteration 异常
生成器
是一种特殊的迭代器,是使用 yield 关键字定义的函数。生成器可以保存函数的运行状态,每次调用都会从上次中断的地方继续执行
区别:
- 迭代器通过显式地定义类和方法构造,而生成器是更简洁的语法形式
- 生成器会自动实现
__iter__()和__next__()方法,而迭代器需要手动实现
示例:
# 生成器示例
def my_generator():
yield 1
yield 2
yield 3
gen = my_generator()
print(next(gen)) # 输出: 1
# 迭代器示例
class MyIterator:
def __iter__(self):
return self
def __next__(self):
if self.current > 3:
raise StopIteration
self.current += 1
return self.current - 1
iter_obj = MyIterator()
iter_obj.current = 1
print(next(iter_obj)) # 输出: 1
方法类型
普通方法(实例方法)
- 第一个参数必须是
self,用于表示实例 - 可以访问实例对象的所有属性和方法
静态方法(@staticmethod)
- 不接收隐式的
self参数,也不接收cls参数 - 是类中的普通函数,不能直接访问类或实例的属性和方法
类方法(@classmethod)
- 第一个参数是
cls,表示类本身 - 类方法可以访问类属性,或者通过类名操作类级别的信息
示例:
class MyClass:
class_variable = "class_value"
def instance_method(self):
return "instance method called", self
@classmethod
def class_method(cls):
return "class method called", cls
@staticmethod
def static_method():
return "static method called"
# 使用实例调用普通方法
obj = MyClass()
print(obj.instance_method())
# 使用类调用类方法
print(MyClass.class_method())
# 使用类调用静态方法
print(MyClass.static_method())
装饰器
装饰器是 Python 中的一种设计模式,用于在函数运行前后扩展其功能,而不改变函数本身的实现。
核心原理: 将一个函数作为参数传递给另一个函数,然后返回一个新的函数
简单装饰器示例:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Function {func.__name__} is being called with arguments: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} returned: {result}")
return result
return wrapper
@logger
def add(a, b):
return a + b
add(3, 5)
执行结果:
Function add is being called with arguments: (3, 5), {}
Function add returned: 8
垃圾回收机制
Python 使用自动垃圾回收机制回收不再使用的内存。
引用计数: 当对象的引用计数为 0 时,内存会被标记为可回收
循环引用问题:
- 如果两个或多个对象相互引用但不被其他部分引用,比如 A 引用 B,B 引用 A,则它们的引用计数不会归 0,导致内存泄漏
解决方案:
- Python 的垃圾回收器使用 "分代收集器" 来检测循环引用
- 垃圾回收器会周期性地检查对象图,将不可达的循环对象也清除
示例:
import gc
class A:
def __init__(self):
self.ref = None
a = A()
b = A()
a.ref = b
b.ref = a
# 打破循环引用
del a
del b
gc.collect() # 强制触发垃圾回收器
线程安全
在多线程环境中,可能会遇到多个线程同时访问共享资源的情况,从而导致线程安全问题。
解决方法:
使用锁(Lock)进行同步
示例:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
# 使用锁保护临界区
with lock:
for _ in range(100000):
counter += 1
threads = []
for _ in range(5):
t = threading.Thread(target=increment)
t.start()
threads.append(t)
for t in threads:
t.join()
print(counter) # 确保线程安全,(可能输出 500000)
元类(metaclass)
元类是用于控制类的行为的 "类的类",通过定制元类可以影响类的创建过程。
核心概念:
- 每个类本身也是对象,其类型就是元类(默认是
type) - 自定义元类可以通过重写元类的
__new__和__init__方法,来定制类的实例化逻辑,属性检查,或者动态注入方法
典型应用场景:
- 实现单例模式
- 在类中自动添加某些属性
- 检查类是否符合某些规则
示例:
class MyMeta(type):
def __new__(cls, name, bases, dct):
print(f"Creating class {name}")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=MyMeta):
pass
# 输出: Creating class MyClass
性能优化
1. 选择合适的数据结构
使用 deque 替代列表,set 替代列表查找等
2. 使用生成器 避免创建庞大列表,改为按需生成数据
3. 内置函数
使用 map、filter、sum 等内置函数
4. 多线程和多进程 针对 I/O 密集型使用多线程,针对 CPU 密集型使用多进程
5. C 扩展库
使用 NumPy 和 cython 执行耗时计算
6. 避免过多的全局变量 减少作用域范围,加快变量查找
7. Profiling 和代码优化
使用工具(如 cProfile、line_profiler)找出性能瓶颈,优化关键部分
挂载
主机:已存在的目录不会重新覆盖创建,之前的权限也不会改变
容器内:已存在的目录不会重新覆盖创建,之前的权限也不会改变
容器内修改目录权限会同步到主机
如果主机设置的只有root可读写,且容器非root运行。则读取挂载会报错