如何将SymEngine生成的lambdify函数保存并在新会话加载?
我需要先完成大量符号表达式计算并保存,后续用于多个大规模Metropolis蒙特卡洛模拟。先后试过Sympy和Symbolics,最终选择SymEngine,因为它在所有相关步骤中的速度明显更快。
使用SymEngine时,生成函数的耗时主要不在符号计算,而是lambdify过程。因此我希望直接保存lambdify生成的函数而非符号表达式,但一直无法在新会话中成功加载。
BSON序列化的复现问题
我最初尝试用BSON保存,相关论坛帖子提到过这种方法,但仅在同一会话内加载有效。以下是复现代码:
保存代码
using SymEngine using BSON: @save, @load function mwe() @vars X f = X return(lambdify(f,[X])) end f = mwe() @save "test.bson" f
新会话加载代码
using SymEngine using BSON: @save, @load function mwe() @vars X f = X return(lambdify(f,[X])) end @load "test.bson" f println(f(1)) f = "nofunction" @load "test.bson" f println(f(1))
执行结果
- 同一会话运行时输出符合预期:
1 1
- 新会话运行第二部分时报错:
ERROR: UndefVarError: ###312 not defined
其他序列化方法的问题
我还尝试了Serialization、FileIO和JLD2等常规序列化方法,结果类似:同会话内加载正常,但新会话加载时要么报错,要么弹出警告且行为异常。
目前唯一可行的方法是用Symbolics的write("test.jl", string(f)),但Symbolics的速度远慢于SymEngine,并非理想方案。
PackageCompiler变通方案失败
我尝试用PackageCompiler生成sysimage作为替代方案:思路是创建一个模块完成所有符号计算,再定义包含所有lambdify表达式列表的常量,然后生成该模块的sysimage,期望在使用该sysimage启动的新会话中能直接使用这些函数。
如果不生成这个常量,创建sysimage的过程正常;但添加const Bookofterms = generate_terms(3,3)(生成函数列表的代码)后,出现冗长错误:
ERROR: The following 1 direct dependency failed to precompile: TimeInt [14fa5fd4-ce9e-41c9-8e49-66abaaa3fbcd]
(TimeInt是我自己的自定义包)
Failed to precompile TimeInt [14fa5fd4-ce9e-41c9-8e49-66abaaa3fbcd] to C:\Users\... ERROR: LoadError: ArgumentError: Expression does not lambdify
caused by: Evaluation into the closed module `SymEngine` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `SymEngine` with `eval` during precompilation - don't do this.
我完全不清楚问题出在哪里。
更新:几天后未得到回复,我把这个帖子复制到了Julia论坛的相关主题下。
内容的提问来源于stack exchange,提问作者Zaph

