Lua - 重置脚本状态而不修复它
Lua - Reseting the state of a script without reparsing it
我有一个 运行s Lua 脚本的应用程序。每个 Lua 脚本可能 运行 多次。某些脚本甚至可能 运行 每次按下一个键。
我希望这些脚本 "reset" 在每个 运行 之间。也就是说,如果用户设置了一个变量 Foo,那么下次 Foo 不应该存在于脚本中 运行s 直到用户再次定义它。
问题是,如果我想有这样的行为,我需要每次都创建一个新的lua_State,然后每次都打开库,然后每次都解析脚本文件,这似乎很未优化。
加载库可能是一个相当轻量级的操作(我假设),但解析脚本可能不是。
有没有办法在不创建新的 lua_State 并重新解析整个 Lua 脚本的情况下重置 Lua 脚本的状态(即清除用户代码定义的变量)文件 ?我只希望脚本文件在应用程序启动时被解析一次,因为它们在 运行 时间没有被修改。
谢谢。 :)
EDIT:我找到了这个主题,但没有详细说明如何做:http://lua-users.org/lists/lua-l/2006-01/msg00493.html
EDIT : lua_setfenv 似乎与此有关。我再挖一点。
EDIT :从 LUA 5.2 开始似乎不再有 lua_setfenv。因为我使用的是 5.3,所以我必须设置环境(即隐藏的 table 命名为 _ENV,其中存储变量)才能做到这一点,从而重新加载所有内容,这是我不想做的...... .
你不能清除lua_State吗?删除所有线程和手动设置的全局变量。您可能需要将用户环境与全局环境分开。
不幸的是,我上次调查这个问题的答案是否定的。
您还需要记住 Lua 可能会调用库,可能会打开文件,malloc()
内存等,并且任何 'reset' 都需要处理关闭这些文件,释放内存等
作为 'resetting' Lua 状态的替代方案,您可以简单地组织您的代码,使其不需要重置;这显然需要以特定方式编写 Lua 代码。一种方法是坚持您的 Lua 代码完全(或几乎完全)包含在函数中,并为每个操作调用一个或多个函数。函数外部的代码可能(例如)return a Lua table 由调用特定入口点的引用组成;这只会被调用一次。函数在调用时会自行清除,包括清除任何库分配的项目、打开的文件等。应避免使用全局变量(除非常量)。我们成功地使用这种方法来确保 Lua 只被解析一次,入口点被确定一次,但是可以非常快速地调用相对较小的函数,开销很小。
在您建议的注释中,您可以将 Lua 代码按词法包装在一个功能块中。我认为这不如上面的方法灵活,并且有以下缺点:
您失去了执行 'one time init' 的机会(例如,从磁盘读取固定常量)
如果用户在他们的代码中插入(例如)不匹配的 end ... function B()
,您将面临不可预测的table风险
您将自己限制在每个 Lua 状态一个入口点。
这确实意味着 Lua 代码必须以不同的方式编写(本质上,Lua 编码器以所需的形式提供代码)。解决此问题的一种可能方法是使用固定框架来执行此操作,并在代码中使用 require
作为库调用。我没有尝试过这种方法。
如果您想确保 lua_State 在每次脚本调用时都相同,您还可以尝试以下适用于我的情况的方法:
- 将自定义内存分配器传递给 lua_newstate,后者从内存池中分配内存
- 在解析脚本之后,在第一个 "run" 之前,在其他内存位置创建内存池的备份
- 每次 "run" 从备份恢复内存池后,在原始位置
请注意,这只处理完全包含在 Lua 数据结构中的资源,而不处理以任何方式从 Lua 或 [=33= 引用的 "external" 资源] 库(例如文件描述符、用户数据...)
因此,在我的例子中,我还通过替换全局变量 table.
使用这种方法,重置基本上可以归结为每次 "run" 之后的一些 memcpy
调用,因此只要需要复制 Lua 结构使用的内存即可为您的脚本。
我有一个 运行s Lua 脚本的应用程序。每个 Lua 脚本可能 运行 多次。某些脚本甚至可能 运行 每次按下一个键。
我希望这些脚本 "reset" 在每个 运行 之间。也就是说,如果用户设置了一个变量 Foo,那么下次 Foo 不应该存在于脚本中 运行s 直到用户再次定义它。
问题是,如果我想有这样的行为,我需要每次都创建一个新的lua_State,然后每次都打开库,然后每次都解析脚本文件,这似乎很未优化。
加载库可能是一个相当轻量级的操作(我假设),但解析脚本可能不是。
有没有办法在不创建新的 lua_State 并重新解析整个 Lua 脚本的情况下重置 Lua 脚本的状态(即清除用户代码定义的变量)文件 ?我只希望脚本文件在应用程序启动时被解析一次,因为它们在 运行 时间没有被修改。
谢谢。 :)
EDIT:我找到了这个主题,但没有详细说明如何做:http://lua-users.org/lists/lua-l/2006-01/msg00493.html
EDIT : lua_setfenv 似乎与此有关。我再挖一点。
EDIT :从 LUA 5.2 开始似乎不再有 lua_setfenv。因为我使用的是 5.3,所以我必须设置环境(即隐藏的 table 命名为 _ENV,其中存储变量)才能做到这一点,从而重新加载所有内容,这是我不想做的...... .
你不能清除lua_State吗?删除所有线程和手动设置的全局变量。您可能需要将用户环境与全局环境分开。
不幸的是,我上次调查这个问题的答案是否定的。
您还需要记住 Lua 可能会调用库,可能会打开文件,malloc()
内存等,并且任何 'reset' 都需要处理关闭这些文件,释放内存等
作为 'resetting' Lua 状态的替代方案,您可以简单地组织您的代码,使其不需要重置;这显然需要以特定方式编写 Lua 代码。一种方法是坚持您的 Lua 代码完全(或几乎完全)包含在函数中,并为每个操作调用一个或多个函数。函数外部的代码可能(例如)return a Lua table 由调用特定入口点的引用组成;这只会被调用一次。函数在调用时会自行清除,包括清除任何库分配的项目、打开的文件等。应避免使用全局变量(除非常量)。我们成功地使用这种方法来确保 Lua 只被解析一次,入口点被确定一次,但是可以非常快速地调用相对较小的函数,开销很小。
在您建议的注释中,您可以将 Lua 代码按词法包装在一个功能块中。我认为这不如上面的方法灵活,并且有以下缺点:
您失去了执行 'one time init' 的机会(例如,从磁盘读取固定常量)
如果用户在他们的代码中插入(例如)不匹配的
end ... function B()
,您将面临不可预测的table风险
您将自己限制在每个 Lua 状态一个入口点。
这确实意味着 Lua 代码必须以不同的方式编写(本质上,Lua 编码器以所需的形式提供代码)。解决此问题的一种可能方法是使用固定框架来执行此操作,并在代码中使用 require
作为库调用。我没有尝试过这种方法。
如果您想确保 lua_State 在每次脚本调用时都相同,您还可以尝试以下适用于我的情况的方法:
- 将自定义内存分配器传递给 lua_newstate,后者从内存池中分配内存
- 在解析脚本之后,在第一个 "run" 之前,在其他内存位置创建内存池的备份
- 每次 "run" 从备份恢复内存池后,在原始位置
请注意,这只处理完全包含在 Lua 数据结构中的资源,而不处理以任何方式从 Lua 或 [=33= 引用的 "external" 资源] 库(例如文件描述符、用户数据...)
因此,在我的例子中,我还通过替换全局变量 table.
使用这种方法,重置基本上可以归结为每次 "run" 之后的一些 memcpy
调用,因此只要需要复制 Lua 结构使用的内存即可为您的脚本。