Lua - 重置脚本的状态而不需要重新解析它

我有一个运行 Lua 脚本的应用程序。每个 Lua 脚本可能会运行多次。有些脚本甚至可能每次按键时都会运行。

我希望在每次运行之间重置这些脚本。也就是说,如果用户设置了一个变量 Foo,那么在下一次运行时脚本中就不应该存在 Foo,直到用户再次定义它。

问题在于,如果我想要这样的行为,就需要每次创建一个新的 lua_State,然后每次都打开库,每次解析脚本文件,这显然是非常不优化的。

加载库可能是一个相当轻量级的操作(我认为),但解析脚本可能不是。

有没有一种方法可以重置 Lua 脚本的状态(即清除用户定义的变量),而不需要创建一个新的 lua_State 并重新解析整个 Lua 脚本文件?我希望在应用程序启动时只需要解析一次脚本文件,因为它们在运行时不会被修改。

谢谢。:)

EDIT : 我找到了这个帖子,但它并没有详细说明如何做到这一点:http://lua-users.org/lists/lua-l/2006-01/msg00493.html

EDIT : lua_setfenv 似乎与此相关。我会再深入一些。

EDIT : 看起来在 LUA 5.2 中已经没有 lua_setfenv 了。由于我正在使用 5.3,我需要设置环境(即一个名为 _ENV 的隐藏表,其中存储变量)才能做到这一点,并重新加载所有内容,而这正是我不想做的...

点赞
用户5352026
用户5352026

问题描述

无法清除lua_State?删除所有线程和手动设置的全局变量。您可能需要将用户环境与全局环境分开。

翻译结果

Can't you clear the lua_State? Remove all threads and the manually set globals. You might need to have the user environment separate from the global environment.

难道您不能清除lua_State吗?请删除所有线程和手动设置的全局变量。您可能需要让用户环境与全局环境分开。

2016-02-16 14:37:13
用户3177124
用户3177124

上次我了解过这个问题,但很遗憾,答案是否定的。

你还需要记住 Lua 可能调用库,打开文件,调用 malloc() 等等操作,任何“重置”的操作都需要关闭这些文件,释放这些内存等等。

作为重置 Lua 状态的替代方式,你可以简单地组织你的代码,使其不需要重置;这显然需要特定的 Lua 代码编写方式。一种方法是坚持让你的 Lua 代码完全(或几乎完全)包含在函数中,并针对每个动作调用一个或多个函数。函数外的代码(例如)可能返回一个 Lua 表,其中包含调用特定入口点的引用;这只会被调用一次。当调用函数时,它会自清,包括清理任何库分配的项,打开文件等等。应该避免使用全局变量(除非是常量)。我们成功地使用这种方法来确保仅解析一次 Lua,仅在入口点确定一次,但可以非常快速地调用相对较小的函数,并且带有很少的开销。

在评论中,你建议将 Lua 代码在函数块中进行词法包装。我认为这种方法比上述方法不够灵活,具有以下缺点:

  • 你失去了进行“一次性初始化”的机会(例如从磁盘读取一个固定常量)

  • 如果用户插入(例如)一个不匹配的 end ... function B() 在他们的代码中,你会面临不可预测的问题

  • 你将自己限制在一个 Lua 状态的一个入口点中。

这意味着 Lua 代码必须以不同的方式编写(实质上,Lua 编写者正在以所需的形式提供代码)。可行的一种方法是使用一个固定的框架来实现这一点,并在需要被调用的代码中使用 require。我没有尝试过这种方法。

2016-02-16 15:03:19
用户10863803
用户10863803

如果您想确保每次脚本调用时 lua_State 是相同的,那么您还可以尝试以下方法,这在我的情况下运行正常:

  • 为 lua_newstate 传递自定义内存分配器,该分配器从内存池分配内存
  • 在解析脚本之后,在第一次“运行”之前,在某个其他内存位置创建内存池的备份
  • 在每个“运行”之后,从备份中还原内存池,回到原始位置

请注意,这仅关注完全包含在 Lua 数据结构中的资源,而不涉及从 Lua 或 Lua 库以任何方式引用的“外部”资源(例如文件描述符、用户数据等)。

因此,在我的情况下,我还通过替换全局表来限制脚本编写者的能力,只提供对上述用法认为安全的操作。

使用这种方法,重置基本上归结为每次“运行”后一些 memcpy 调用,因此需要复制为脚本使用的 Lua 结构体的内存所需的时间。

2019-01-03 16:48:03