我正在开发一个工具,用于用户定义函数的一些数值分析。我们的想法是在Python中创建一个方便的UI,用户可以在其中输入C函数,然后按下按钮-并接收一些输出数据。计算可能需要几分钟或几个小时,因此仅使用numpy的性能是不可接受的。
我尝试了以下方法:基于python的UI调用gcc,从用户函数编译dll,而不是在Cython包装中使用我的核心基于c的算法。它可以工作,但由于没有办法完全卸载python模块,我不能重新编译用户定义的函数,直到整个UI程序关闭并再次运行。
我现在看到的唯一方法是将计算核心和UI进程分开,然后使它们通过共享内存/消息传递进行交互。当用户想要更新他的函数时,程序终止内核,重新编译dll并重新启动内核。
在这种情况下,你能提出什么常规做法吗?谢谢!
Python具有非常好的多进程支持(并且实际上不是很好的线程支持),因此您可以为每个要求值的表达式生成一个新的Python进程,在新进程中编译和加载dll,然后让它将结果传递回父进程。当生成的进程退出时,所有的东西都应该被卸载。
每次用户输入一个函数时,您都可以生成一个具有随机唯一名称的新模块(就像您对临时文件所做的那样)。然后编译该模块,加载它,并调用该函数。
随着时间的推移,这当然会导致大量模块被加载。如果用户不会在一个会话中运行太多的函数,那么您可能会侥幸成功。或者,您可以在一个普通的DLL而不是Python模块中编译该函数,并使用ctypes加载它。当您使用完DLL后,只需丢弃对它的任何引用——当ctypes句柄最终被删除时,它应该卸载DLL(参见如何在Python中使用ctypes卸载DLL ?您可能还想从磁盘上删除dll。如果你使用的是Windows,这可能会很棘手,因为很难预测ctypes何时会卸载它,而且如果它正在使用,Windows不会让你删除它。
您考虑过Weave或Instant(更新较慢)吗?我自己只使用过instant,但是对于你所描述的内容,这两种方法都是完美的。
它们都可以在运行时从字符串自动编译和缓存c代码。我只使用过instant来内联c,但我相信它或weave在编译用户输入时也会工作得很好。
这是一个如何使用weave的例子,来自教程。
>>> a = 'string'
>>> def protected_printf(a):
... assert(type(a) == type(1))
... weave.inline(r'printf("%dn",a);',['a'])
>>> protected_printf(1)
1
>>> protected_printf('string')
AssertError...