Lua 取毫秒,微秒

本文介绍了一种在Lua中实现毫秒及微秒级别时间获取的方法,通过编写C语言扩展来实现更精确的时间戳获取,避免了引入额外库的复杂性。

Lua自带的os函数,os.time()只取到秒。网上搜索lua 毫秒都是要使用 luasocket,觉得真没那个必要为了一个函数,用一套用不上的东西。试着写了个扩展,代码如下。

C语言:


#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <lua.h>
#include <lauxlib.h>

//微秒
static int getmicrosecond(lua_State *L) {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    long microsecond = tv.tv_sec*1000000+tv.tv_usec;
    lua_pushnumber(L, microsecond);
    return 1;
}

//毫秒
static int getmillisecond(lua_State *L) {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    long millisecond = (tv.tv_sec*1000000+tv.tv_usec)/1000;
    lua_pushnumber(L, millisecond);
    
    return 1;
}


int luaopen_usertime(lua_State *L) {
  luaL_checkversion(L);

  luaL_Reg l[] = {
    {"getmillisecond", getmillisecond},
    {"getmicrosecond", getmicrosecond},
    { NULL, NULL },
  };

  luaL_newlib(L, l);
  return 1;
}


编译命令: cc -g -O2 -Wall -fPIC --shared usertime.c -o usertime.so

Lua调用:


local utime = require "usertime"

local microsecond = utime.getmicrosecond()
local millisecond = utime.getmillisecond()

print('microsecond',microsecond)
print('millisecond',millisecond)

转载于:https://my.oschina.net/u/1053317/blog/542871

<think>我们正在讨论 Redis 中的 Lua 垃圾回收机制,特别是 `luaC_step` 函数。 根据 Redis 源码,Lua 环境使用增量垃圾回收(Incremental Garbage Collection),`luaC_step` 是触发单步垃圾回收的关键函数。 函数作用: 1. **渐进式垃圾回收**:Redis 为避免一次性垃圾回收造成长时间阻塞,将回收过程拆分为多个小步骤。`luaC_step` 每次调用执行一步回收操作。 2. **内存控制**:Redis 通过 `luaC_step` 控制 Lua 内存使用,防止 Lua 脚本占用过多内存影响主服务。 在 Redis 源码中的应用: - 位置:`src/scripting.c` 和 `src/lua.c` 中。 - 触发时机:通常在事件循环(如 `beforeSleep` 函数)中调用,确保每次事件循环处理少量垃圾回收工作。 - 相关配置:`lua-time-limit` 设置 Lua 脚本执行的最大时间(默认 5000 毫秒)。在脚本执行超时后,Redis 会尝试中断脚本,并定期调用 `luaC_step` 进行垃圾回收。 关键代码片段(Redis 6.2 版本): ```c void luaC_step(void) { lua_gc(server.lua, LUA_GCSTEP, 100); // 执行单步垃圾回收,步长为100 } ``` 说明: - `lua_gc` 是 Lua C API 提供的垃圾回收控制函数。 - `LUA_GCSTEP` 表示执行增量步骤,步长(这里是100)控制单步回收的工作量。 垃圾回收过程: 1. **标记阶段**:遍历所有对象,标记活跃对象。 2. **清理阶段**:回收未标记对象的内存。 由于 Lua 使用分代垃圾回收(Lua 5.1 后为增量标记清除),`luaC_step` 每次执行一小部分工作。 性能考虑: - 避免阻塞:单步执行时间短,不会阻塞 Redis 主线程过久。 - 内存压力:当 Lua 内存增长过快时,`luaC_step` 会加快回收速度(通过调整步长或频率)。 示例场景: 1. 用户执行一个大型 Lua 脚本,创建许多临时对象。 2. 脚本执行完毕后,Redis 在事件循环中逐步调用 `luaC_step` 回收这些对象。 相关问题: 1. Redis 如何中断运行超时的 Lua 脚本? 2. Lua 垃圾回收的算法细节是什么? 3. 如何调整 Redis 的 Lua 内存限制? 注意:在 Redis 7.0 中,Lua 引擎升级到 Lua 5.4,但 `luaC_step` 的基本机制保持不变。</think>在 Redis 源码中,`luaC_step()` 函数是 **Lua 垃圾回收(GC)的增量执行机制**的核心实现,用于分步执行 Lua 虚拟机的垃圾回收过程,避免一次性全量回收造成的长时间阻塞。以下是详细解析: --- ### **核心作用** 1. **增量式垃圾回收** 通过多次调用 `luaC_step()` 将完整的 GC 过程拆解为多个小步骤执行,每次仅处理少量内存回收。 数学表示为: $$ \text{GC\_work} = \sum_{i=1}^{n} \text{luaC\_step()} $$ 其中 $n$ 为步骤数,避免单次 $\int_{0}^{T} \text{Full\_GC}$ 的长时阻塞。 2. **避免服务阻塞** Redis 作为单线程服务,若 Lua 脚本触发全量 GC(如 `lua_gc(L, LUA_GCCOLLECT, 0)`),会导致微秒级延迟激增。 `luaC_step()` 将 GC 工作分摊到多次事件循环中,每次执行约 **100 个 GC 单元**(Lua 内部单位)[^1]。 --- ### **在 Redis 源码中的应用** #### 1. **触发位置** - **事件循环钩子**:在 `beforeSleep()` 函数(`src/server.c`)中调用,确保每次事件循环执行少量 GC: ```c void beforeSleep(struct aeEventLoop *eventLoop) { if (server.lua_caller) luaC_step(); // 执行单步GC } ``` - **Lua 内存阈值检测**:当 Lua 内存使用接近 `lua_memory_limit` 时主动触发(`src/scripting.c`)。 #### 2. **实现机制** ```c // src/lua.c void luaC_step(void) { // 步长=100,对应Lua的GCSTEP操作 lua_gc(server.lua, LUA_GCSTEP, 100); // 记录GC耗时(用于超时处理) server.lua_gc_elapsed += elapsedMs(...); } ``` - **`LUA_GCSTEP`**:Lua C API 的增量回收指令,参数 `100` 控制单步工作量。 - **耗时监控**:统计 GC 时间,防止累计超时(受 `lua-time-limit` 约束)。 #### 3. **与超时中断协同** 当 Lua 脚本执行超时(默认 5 秒)时: 1. Redis 标记 `SCRIPT KILL` 标志 2. 后续 `luaC_step()` 调用中,若检测到超时且脚本允许中断,则抛出 `LUA_ERRGCMM` 错误[^2]: ```c if (server.lua_timedout && server.lua_caller->flags & CLIENT_SCRIPT) { lua_pushstring(server.lua, "Script interrupted by timeout"); lua_error(server.lua); // 强制终止脚本 } ``` --- ### **设计必要性** 1. **实时性保障** 单步 GC 耗时通常 $<1ms$,避免影响 Redis 的 $\leq 1ms$ 低延迟要求。 2. **内存安全** 防止恶意 Lua 脚本通过内存泄露耗尽资源(如递归生成垃圾数据): ```lua function attack() local t = {} while true do t[#t+1] = {} end -- 快速生成垃圾对象 end ``` `luaC_step()` 会逐步回收这些对象。 3. **公平调度** 在事件循环中穿插 GC 任务,避免独占 CPU。 --- ### **性能优化参数** | 参数 | 默认值 | 作用 | |-----------------------|--------|-------------------------------| | `lua-time-limit` | 5000ms | 脚本最大执行时间(含GC时间) | | `lua-memory-limit` | 0 (无限制) | Lua可用的最大内存(字节) | | `lua-replicate-commands` | yes | 防止脚本副作用导致GC激增 | --- ### **相关问题** 1. Redis 如何中断运行超时的 Lua 脚本? 2. Lua 垃圾回收的标记-清除算法具体如何工作? 3. 如何通过 `lua_memory_limit` 防止 Lua 内存泄露? 4. Redis 7.0 的 `Function` 特性与 Lua 脚本的 GC 机制有何异同? [^1]: 参见 Redis 源码 `src/lua.c` 中的 `luaC_step` 实现。 [^2]: 超时处理逻辑详见 `src/scripting.c` 的 `evalGenericCommand` 函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值