缓存说明
Numba 支持将编译后的函数缓存到文件系统中,以便将来使用相同的函数。
实现
缓存是通过保存编译后的 目标代码 ,即可执行代码的 ELF 对象来实现的。通过使用 目标代码 ,缓存函数具有最小的开销,因为不需要编译。缓存数据保存在缓存目录下(参见 NUMBA_CACHE_DIR
)。缓存的索引存储在一个 .nbi
文件中,每个函数一个索引,并列出了为该函数编译的所有重载签名。目标代码 存储在扩展名为 .nbc
的文件中,每个重载一个文件。两个文件中的数据都使用 pickle
进行序列化。
缓存能力的要求
开发者应注意函数的要求,以允许其被缓存,确保他们正在开发的功能与缓存兼容。
可缓存函数的要求:
LLVM 模块必须是 自包含的,这意味着它不能依赖于其他未链接的编译单元。
唯一允许的外部符号来自 NRT 或其他系统库中的常见符号(例如 libc 和 libm)。
调试笔记:
在LLVM IR中查找
inttoptr
的使用,或在Python的lowering代码中查找target_context.add_dynamic_add()
的使用。它们指示了潜在的运行时地址使用。并非所有使用都是问题,有些是必要的。只有将常量整数转换为指针会影响缓存。滥用动态地址或动态符号很可能会导致段错误。
链接顺序很重要,因为未使用的符号在链接后会被丢弃。链接应从依赖图的叶节点开始。
与缓存兼容的功能
以下功能已明确验证可与缓存一起使用。
cpu
和parallel
目标的 ufuncs 和 gufuncs并行加速器功能(即
parallel=True
)
缓存限制
这是缓存已知限制的列表:
缓存失效未能识别在不同文件中定义的符号的变化。
全局变量被视为常量。缓存会记住全局变量在编译时的值。在缓存加载时,缓存函数不会重新绑定到全局变量的新值。
缓存共享
在不同机器上共享和重用缓存目录中的内容是安全的。缓存在编译期间会记住CPU型号和可用的CPU特性。如果CPU型号和CPU特性不完全匹配,缓存内容将不会被考虑。(另见 NUMBA_CPU_NAME
)
如果缓存目录在网络文件系统上共享,只有当文件替换操作对文件系统来说是原子操作时,缓存的并发读/写才是安全的。Numba总是先写入一个唯一的临时文件,然后用临时文件替换目标缓存文件路径。Numba对丢失的缓存文件和丢失的缓存条目具有容忍性。
缓存清除
当相应的源文件被修改时,缓存会失效。然而,有时需要手动清除缓存目录。例如,编译器的变化不会被识别,因为源文件没有被修改。
要清除缓存,可以简单地删除缓存目录。
在Numba应用程序运行时删除缓存目录可能会导致在编译位置引发 OSError
异常。