缓存注意事项
Numba 支持将编译后的函数缓存到文件系统,以便将来再次使用这些函数。
实现
缓存通过保存编译后的*目标代码*实现,即可执行代码的 ELF 对象。使用*目标代码*可以使缓存的函数开销最小化,因为无需再次编译。缓存数据保存在缓存目录下(参见 NUMBA_CACHE_DIR
)。缓存的索引存储在 .nbi
文件中,每个函数一个索引,其中列出了为该函数编译的所有重载签名。*目标代码*存储在扩展名为 .nbc
的文件中,每个重载一个文件。这两种文件中的数据都使用 pickle
进行序列化。
可缓存性要求
开发人员应注意函数可被缓存的各项要求,以确保他们正在开发的功能与缓存兼容。
可缓存函数的要求
LLVM 模块必须是*自包含的*,这意味着它不能在不链接到其他编译单元的情况下依赖它们。
唯一允许的外部符号来自 NRT 或来自系统库(例如 libc 和 libm)的其他常见符号。
调试注意事项
在 LLVM IR 中查找
inttoptr
的用法,或在 Python 的降低代码中查找target_context.add_dynamic_add()
。它们表示可能使用了运行时地址。并非所有用法都有问题,有些是必需的。只有将常量整数转换为指针才会影响缓存。动态地址或动态符号的误用很可能导致段错误(segfault)。
链接顺序很重要,因为未使用的符号在链接后会被丢弃。链接应从依赖图的叶节点开始。
缓存共享
在不同的机器上共享和重用缓存目录中的内容是安全的。缓存在编译时会记住 CPU 型号和可用的 CPU 功能。如果 CPU 型号和 CPU 功能不完全匹配,缓存内容将不被考虑。(另请参见 NUMBA_CPU_NAME
)
如果缓存在网络文件系统上共享,则只有在文件替换操作对于文件系统是原子性的情况下,缓存的并发读写才是安全的。Numba 总是首先写入一个唯一的临时文件,然后用该临时文件替换目标缓存文件路径。Numba 对丢失的缓存文件和丢失的缓存条目具有容错性。
缓存清除
当对应的源文件被修改时,缓存会失效。但是,有时需要手动清除缓存目录。例如,编译器的更改将不会被识别,因为源文件未被修改。
要清除缓存,可以直接删除缓存目录。
在 Numba 应用程序运行时删除缓存目录可能会在编译时引发 OSError
异常。