Open w4454962 opened 1 year ago
最简单的办法不是避免这种用法吗
你脱离作图1线 异步创建table 是很难避免的, 除非将所有异步的接口分离,单独一个虚拟机, 同步接口单独一个虚拟机, 否则一定存在异步创建table的情况的, 比如 message.hook 你自己就异步创建了table push给lua了。。。
我是说避免遍历key是gc对象的table
总是会有这种需求的。 再者遍历 key=string是硬需求, 但是在编写过程中很容易疏忽 导致一个表里 不止是string 有可能存在其他的obj 这时候就异步了。 lua产生异步的概率还是非常高的
key是string,只需要统一string的hash值就可以解决
我知道, 但是在编写的过程中,很容易疏忽, 让一个表的key不完全是string ,而且一些新人入坑的 完全不知道这个问题,在编写完几万行代码后发现地图异步,几乎如同海底捞针。
检查pairs和next,不符合要求就抛错
这是不得以而为之的办法。 dream big
就1楼的方案 专门看了一下 luaL_traceback 的源码 发现效率低的原因有2个
1 字符串格式化 字符串连接 这些操作 2 5.3之后 为了读取 文件返回表时 函数字段名称 递归了package.loaded里所有的表 去匹配相同函数值的字段名 导致效率低下
所以针对这2个问题 去掉一些无用信息 就遍历调用栈 取关键信息进行哈希 节省字符串格式化/连接 这些操作 就可以极大的提高 获取调用栈哈希值 信息的效率。
应该还是可行性的 等后面有空的时候我再实际操作一个版本试试。
同位置也会有异步的table鸭
local res
for i = 1, jass.GetPlayerID(jass.GetLocalPlayer()) do
res = {}
end
实际业务中,可能是一个异步的事件执行同一段代码,然后将创建的表保存在全局里以后用。
异步创建的表 混合 同步创建的表 一起作为key 进行遍历 产生的异步 确实可能存在,但是情况还是会比较少的,
大部分情况下 是在同步环境下 创建的表对象 需要在同步的情况下进行pairs 仅仅为满足这个需求。
当然最安全的情况 就是分2个虚拟机 用中间代码进行交互。 但是会带来使用上的负担 影响便捷性
我觉得,与其做一个99%安全的功能,不如完全禁止这个功能。英萌当年就做了 safePairs
与 unsafePairs
的区分,业务层使用默认的 pairs
就是会检查是否安全的,如果一定想要遍历需要使用另一个API,让用户知道这么做有风险,这样用户才会自己仔细检查。
pairs之所以异步 是因为 没办法给table分配一个 所有玩家都一致的 index,
1.32 在每个table创建时 自动分配一个独立的index ,但是因为本地玩家/异步事件 会在异步时机创建table,进而导致之后分配的索引异步,从而失败,
所以问题的本质 就是 每个table 需要一个不受其他位置创建table的影响, 而在自己的位置有自己的计数的一个index
所以我想到的解决方案就是 在创建table时, 根据当前lua堆栈 获取一个索引分配器, 进行递增分配索引
所以 最终结果是 index的类型 由 uint64_t 来完成
uint64_t 高位 4字节 由lua调用堆栈 进行哈希算法 由4字节哈希值完成 uint64_t 低位 4字节 由lua调用堆栈 映射的分配器 进行递增 来完成
这样异步环境下 调用 某个函数 生成的table 跟同步环境下 调用 同一个函数 生成的table 他们之间的 index 都是分别独立 不会互相干扰
这样同步产生的table 作为key 进行遍历 就不会异步了
这个方案唯一的问题就是 获取lua调用堆栈的效率过低, 尤其是 lua5.3之后 debug.traceback的效率 相比5.1下降了10倍 所以差最后这个步骤进行闭环。