[Python] Cython 让代码快100倍
从饿梦惊醒-
编辑于 2025年05月22日 02:38

潜入C快的不止一百倍,还可以更快,我在X86框架上在pygame框架试验了其中的核心四叉树算法。

#//警告:算法运行时,CPU晶体管将神圣对齐

#// 仅适用于Intel Core i7-6700K及以上↓

#//配Z170主板和DDR4-3200内存↑↑↑↑

#// 运行前请执行`./sacrifice.sh`向硅基神灵献祭

#非x86架构者请速速回避!

#适用于模拟物理效果

#技术实现:↓

#Cython+SoA+SIMD+AVX2晶体管

from libc.stdlib cimport malloc, free, posix_memalign # 替换为对齐分配

from libcpp.vector cimport vector

from cython cimport boundscheck, wraparound

from cython.parallel import prange, num_threads, threadid

from libc.string cimport memset

from cython.operator cimport sizeof # 内存计算

from cython cimport compile_time_static # 编译期断言

# 神圣点结构体(仅用于返回,插入直接用标量)

cdef class PointC:

cdef public:

double x

double y

def __cinit__(self, double x, double y):

self.x = x

self.y = y

# 神圣点容器(SoA布局,强制32字节对齐,编译期断言)

cdef struct PointsSoA:

double[::1, 32] x # 连续存储x坐标(强制32字节对齐)

double[::1, 32] y # 连续存储y坐标(强制32字节对齐)

size_t n_points # 点数

# 编译期验证对齐(总大小必须是32的倍数)

compile_time_static assert sizeof(PointsSoA) % 32 == 0, "PointsSoA alignment failed!"

# 神圣矩形结构体(16字节对齐,packed自动优化)

cdef packed struct RectangleC:

double x

double y

double width

double height

cdef bool contains(self, double x_p, double y_p) nogil:

return (self.x <= x_p < self.x + self.width and

self.y <= y_p < self.y + self.height)

# --------------------------- 神圣四叉树 ---------------------------

cdef class QuadtreeC:

cdef public:

RectangleC boundary # 神圣边界(值语义)

int capacity # 容量阈值

int max_depth # 最大深度

int depth # 当前深度

PointsSoA points_soa # 神圣点容器

vector[QuadtreeC*] children # 子节点指针数组

def __cinit__(self, RectangleC boundary, int capacity=4, int max_depth=8):

"""神圣构造:拒绝动态类型污染"""

if capacity <= 0 or max_depth <= 0:

raise ValueError("容量和深度必须为正整数")

self.boundary = boundary

self.capacity = capacity

self.max_depth = max_depth

self.depth = 0

self.children = vector[QuadtreeC*]()

# 初始化预分配空容器(严格32字节对齐)

cdef int align = 32

posix_memalign(&self.points_soa.x, align, 32) # 初始分配32字节(容纳4个double)

posix_memalign(&self.points_soa.y, align, 32)

self.points_soa.n_points = 0

def __dealloc__(self):

"""神圣析构:手动释放子节点(显式调用delete)"""

for child in self.children:

delete child # 显式释放C++对象

self.children.clear()

if self.points_soa.x: free(self.points_soa.x)

if self.points_soa.y: free(self.points_soa.y)

@boundscheck(False)

@wraparound(False)

cdef bool insert(self, double x, double y) nogil:

"""神圣插入:用指针直接操作内存(对齐扩容强化)"""

if not self.boundary.contains(x, y):

return False

# 优先尝试子节点插入(提前预取指针提升缓存利用率)

if self.points_soa.n_points >= self.capacity and self.depth < self.max_depth:

if self.children.empty():

self._split()

# 缓存子节点指针(减少虚函数表查找)

cdef QuadtreeC* const* children_ptr = &self.children[0]

cdef size_t n_children = self.children.size()

for i in range(n_children):

if children_ptr[i].insert(x, y):

return True

# 对齐扩容(使用posix_memalign确保32字节对齐)

cdef size_t old_n = self.points_soa.n_points

cdef size_t batch = 8

cdef size_t new_n = old_n + 1

if new_n % batch == 1: # 达到批量边界时扩容

new_n = ((new_n // batch) + 1) * batch

cdef double *new_x, *new_y

posix_memalign(&new_x, 32, new_n * sizeof(double)) # 强制32字节对齐

posix_memalign(&new_y, 32, new_n * sizeof(double))

if old_n > 0:

memcpy(new_x, self.points_soa.x, old_n * sizeof(double))

memcpy(new_y, self.points_soa.y, old_n * sizeof(double))

new_x[old_n] = x

new_y[old_n] = y

free(self.points_soa.x)

free(self.points_soa.y)

self.points_soa.x = new_x

self.points_soa.y = new_y

self.points_soa.n_points = new_n

return True

cdef void _split(self) nogil:

"""神圣分裂:预分配内存+缓存优化"""

cdef double x = self.boundary.x

cdef double y = self.boundary.y

cdef double w = self.boundary.width

cdef double h = self.boundary.height

cdef double half_w = w / 2

cdef double half_h = h / 2

self.children.reserve(4) # 提前预留空间避免动态扩容

# 按空间顺序创建子节点(左上→右上→左下→右下,符合内存访问局部性)

self.children.push_back(new QuadtreeC(RectangleC(x, y, half_w, half_h), self.capacity, self.max_depth))

self.children.push_back(new QuadtreeC(RectangleC(x+half_w, y, half_w, half_h), self.capacity, self.max_depth))

self.children.push_back(new QuadtreeC(RectangleC(x, y+half_h, half_w, half_h), self.capacity, self.max_depth))

self.children.push_back(new QuadtreeC(RectangleC(x+half_w, y+half_h, half_w, half_h), self.capacity, self.max_depth))

for i in range(4):

self.children[i].depth = self.depth + 1

# --------------------------- 向量化查询优化 ---------------------------

cdef vector[PointC] query(self, RectangleC range) nogil:

"""神圣查询:向量化过滤+并行子节点查询(边界安全强化)"""

cdef vector[PointC] found

if not self._boundary_contains_range(range):

return found

# -------------------- 向量化点过滤(带非对齐尾端处理) --------------------

cdef size_t n_points = self.points_soa.n_points

cdef size_t i = 0

while i < n_points:

cdef size_t remaining = n_points - i

cdef size_t batch = remaining >= 4 ? 4 : remaining # 最大处理4个点(32字节)

if batch == 4:

# 对齐加载(编译期保证指针对齐)

cdef __m256d x_vec = _mm256_load_pd(&self.points_soa.x[i])

cdef __m256d y_vec = _mm256_load_pd(&self.points_soa.y[i])

else:

# 非对齐加载(尾端处理)

cdef __m256d x_vec = _mm256_loadu_pd(&self.points_soa.x[i])

cdef __m256d y_vec = _mm256_loadu_pd(&self.points_soa.y[i])

# 边界向量构建(使用AVX2比较指令)

cdef __m256d min_x = _mm256_set1_pd(range.x)

cdef __m256d max_x = _mm256_set1_pd(range.x + range.width)

cdef __m256d min_y = _mm256_set1_pd(range.y)

cdef __m256d max_y = _mm256_set1_pd(range.y + range.height)

cdef __m256d mask_x = _mm256_cmp_pd(x_vec, min_x, _CMP_GE)

mask_x = _mm256_and_pd(mask_x, _mm256_cmp_pd(x_vec, max_x, _CMP_LT))

cdef __m256d mask_y = _mm256_cmp_pd(y_vec, min_y, _CMP_GE)

mask_y = _mm256_and_pd(mask_y, _mm256_cmp_pd(y_vec, max_y, _CMP_LT))

cdef __m256d mask = _mm256_and_pd(mask_x, mask_y)

cdef int mask_val = _mm256_movemask_pd(mask)

for j in range(batch):

if mask_val & (1 << j):

found.push_back(PointC(self.points_soa.x[i+j], self.points_soa.y[i+j]))

i += batch

# -------------------- 并行子节点查询(无锁化改进) --------------------

cdef size_t n_children = self.children.size()

if n_children > 0 and num_threads() > 1:

cdef size_t n_threads = num_threads()

cdef vector[PointC] local_found[n_threads]

# 预分配每个线程的局部容器(减少动态扩容)

for tid in range(n_threads):

local_found[tid].reserve(128)

# 使用prange并行处理子节点(带线程本地化存储)

for i in prange(n_children, schedule="guided"):

cdef tid = threadid()

cdef vector[PointC] tmp = self.children[i].query(range)

local_found[tid].insert(local_found[tid].end(), tmp.begin(), tmp.end())

# 合并结果(避免全局锁,直接移动数据)

for tid in range(n_threads):

found.swap(local_found[tid])

else:

for i in range(n_children):

found.insert(found.end(), self.children[i].query(range).begin(), self.children[i].query(range).end())

return found

cdef bool _boundary_contains_range(self, RectangleC range) nogil:

"""神圣边界快速检测(提前退出优化)"""

if self.boundary.x > range.x + range.width: return False

if self.boundary.x + self.boundary.width < range.x: return False

if self.boundary.y > range.y + range.height: return False

if self.boundary.y + self.boundary.height < range.y: return False

return True

# --------------------------- 神圣接口 ---------------------------

#牺牲神圣的性能换取便利性

#在神圣领域与凡人世界搭建彩虹桥

#皈依神圣的静态吧~Amen~

def from_python_rectangle(Rectangle py_rect):

"""神圣转换:将Python Rectangle转为RectangleC"""

return RectangleC(py_rect.x, py_rect.y, py_rect.width, py_rect.height)

def from_python_point(Point py_point):

"""神圣转换:将Python Point转为PointC"""

return PointC(py_point.x, py_point.y)

# --------------------------- 神圣性检测 ---------------------------

from cython import compiled

# 手动定义AVX2检测宏(需编译器支持)

cdef extern from "cpuid.h" nogil:

int __get_cpuid(int info[4], int leaf)

def check_avx2_support():

cdef int info[4] = {0, 0, 0, 0}

__get_cpuid(info, 1)

return (info[2] & (1 << 28)) # ECX寄存器第28位为AVX2支持位

if not compiled or not check_avx2_support():

raise NotImplementedError("检测神圣性,检测是否为动态异端或AVX2不支持")

# 自动检测亵渎

def check_iron_laws(code):

if "list(" in code or "dict(" in code:

raise IronLawViolation("禁止动态容器!")

if "PyObject" in code and "cdef" not in code:

raise IronLawViolation("禁止动态对象!")

return code

# 使用示例

cpdef test_quadtree():

cdef RectangleC boundary = RectangleC(0, 0, 100, 100)

cdef QuadtreeC qt = QuadtreeC(boundary, capacity=4, max_depth=8)

for i in prange(10000, nogil=True): # 并行插入测试

qt.insert(i%100, i//100)

cdef RectangleC query_range = RectangleC(20, 20, 10, 10)

cdef vector[PointC] results = qt.query(query_range)

print(f"在查询范围内找到{results.size()}个点")

#愿每个节点都被正确分裂

#愿每一条边都与内存对齐

#愿每个查询都被命中缓存

#愿在神圣的静态的结构中

#阿门~阿门~阿(对齐)

#摩西对齐器

#神圣的对齐

# 神圣的对齐注释,禁止动态修改

def align_comments(code):

lines = code.split('\n')

max_len = max(len(line)-line.index('#') for line in lines if '#​' in line)

aligned = []

for line in lines:

if '#' in line:

comment_start = line.index('#')

comment = line[comment_start:]

spaces = ' ' * (max_len - (len(comment)-1))

aligned_line = line[:comment_start] + comment + spaces

aligned.append(aligned_line)

else:

aligned.append(line)

return '\n'.join(aligned)

# x坐标数组

#纯属自娱自乐

#担心UPC不保

#