【问题标题】:Lua - Current time in millisecondsLua - 当前时间(以毫秒为单位)
【发布时间】:2010-10-02 13:30:23
【问题描述】:

有没有一种通用的方法可以以毫秒或毫秒为单位获取当前时间?

os.time(),但它只提供完整的秒数。

【问题讨论】:

  • 我们真的可以在 Lua 中使用合适的日期/时间库。 os.time 和 os.date 通常真的不切。
  • 有时我觉得整个 Lua 真的不适合:P

标签: time lua


【解决方案1】:

我使用 LuaSocket 来获得更高的精度。

require "socket"
print("Milliseconds: " .. socket.gettime()*1000)

这当然会增加一个依赖项,但对于个人使用来说效果很好(例如在基准测试脚本中)。

【讨论】:

  • 请注意,至少有人声称在 Windows 上此实现不够高分辨率:lua-users.org/wiki/HiResTimer
  • 请注意,在我的系统上更新后,这停止工作。我不得不将其更改为socket = require "socket",否则socket 为零。
【解决方案2】:

如果要进行基准测试,可以使用文档中显示的 os.clock:

local x = os.clock()
local s = 0
for i=1,100000 do s = s + i end
print(string.format("elapsed time: %.2f\n", os.clock() - x))

【讨论】:

  • 然而,这似乎以 1/100 秒的精度而不是毫秒。
  • 如果您调用使用线程的 C 函数,这将无法正常工作。而不是实际花费的时间,它报告所有线程花费的时间,作为总和
  • 此函数以及os.time 函数高度依赖于系统。另请注意,文档声明它返回程序使用的 cpu 时间,这在大多数系统上与实际花费的“地球时间”非常不同。
  • 因为我坚持使用标准 Lua 并且它必须是可移植和封装的(没有外部 dll),这是我能找到的最佳解决方案。 +1
  • @ShaneBishop 请参阅页面底部的lua.org/pil/22.1.html
【解决方案3】:

在标准 C lua 中,没有。您将不得不等待几秒钟,除非您愿意自己修改 lua 解释器以让 os.time 使用您想要的分辨率。但是,如果您正在编写代码让其他人自行运行,而不是像您可以完全控制环境的 Web 应用程序那样,这可能是不可接受的。

编辑:另一种选择是用 C 语言编写您自己的小 DLL,该 DLL 使用新函数扩展 lua,该函数将为您提供所需的值,并要求将 dll 与您的代码一起分发给将要使用它的任何人。

【讨论】:

  • DLL 或 .so 等。取决于系统... :-)
  • os.clock() 中返回的小数是多少?
  • @Kousha os.clock 中的小数点是几分之一秒;但是,os.clock 报告的程序执行时间不是真实世界的时间。 os.clock 也是不一致的 arcoss 平台,因为它在 Windows 系统上报告 real timecpu time
【解决方案4】:

以毫秒为单位获取当前时间。

os.time()

os.time()
return sec // only

posix.clock_gettime(clk)

https://luaposix.github.io/luaposix/modules/posix.time.html#clock_gettime

require'posix'.clock_gettime(0)
return sec, nsec

linux/time.h //man clock_gettime

/*
 * The IDs of the various system clocks (for POSIX.1b interval timers):
 */
#define CLOCK_REALTIME                  0
#define CLOCK_MONOTONIC                 1
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3
#define CLOCK_MONOTONIC_RAW             4
#define CLOCK_REALTIME_COARSE           5
#define CLOCK_MONOTONIC_COARSE          6

socket.gettime()

http://w3.impa.br/~diego/software/luasocket/socket.html#gettime

require'socket'.gettime()
return sec.xxx

正如waqas 所说


比较和测试

get_millisecond.lua

local posix=require'posix'
local socket=require'socket'

for i=1,3 do
    print( os.time() )
    print( posix.clock_gettime(0) )
    print( socket.gettime() )
    print''
    posix.nanosleep(0, 1) -- sec, nsec
end

输出

lua get_millisecond.lua
1490186718
1490186718      268570540
1490186718.2686

1490186718
1490186718      268662191
1490186718.2687

1490186718
1490186718      268782765
1490186718.2688

【讨论】:

    【解决方案5】:

    我为 Windows 上的 lua 做了一个合适的解决方案。我基本上按照 Kevlar 的建议做了,但使用的是共享库而不是 DLL。这已经使用 cygwin 进行了测试。

    我编写了一些与 lua 兼容的 C 代码,将其编译为共享库(通过 cygwin 中的 gcc 的 .so 文件),然后使用 package.cpath 将其加载到 lua 中并要求“”。为方便起见,编写了一个适配器脚本。以下是全部来源:

    首先是 C 代码,HighResTimer.c

    ////////////////////////////////////////////////////////////////
    //HighResTimer.c by Cody Duncan
    //
    //compile with:  gcc -o Timer.so -shared HighResTimer.c -llua5.1
    //compiled in cygwin after installing lua (cant remember if I 
    //   installed via setup or if I downloaded and compiled lua, 
    //   probably the former)
    ////////////////////////////////////////////////////////////////
    #include <windows.h>
    
    typedef unsigned __int64 u64;
    double mNanoSecondsPerCount;
    
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
    
    
    int prevInit = 0;
    int currInit = 0;
    u64 prevTime = 0;
    u64 currTime = 0;
    u64 FrequencyCountPerSec;
    
    LARGE_INTEGER frequencyTemp;
    static int readHiResTimerFrequency(lua_State *L)
    {
        QueryPerformanceFrequency(&frequencyTemp);
        FrequencyCountPerSec = frequencyTemp.QuadPart;
        lua_pushnumber(L, frequencyTemp.QuadPart);
        return 1;
    }
    
    LARGE_INTEGER timerTemp;
    static int storeTime(lua_State *L)
    {
        QueryPerformanceCounter(&timerTemp);
    
        if(!prevInit)
        {
            prevInit = 1;
            prevTime = timerTemp.QuadPart;
        }
        else if (!currInit)
        {
            currInit = 1;
            currTime = timerTemp.QuadPart;
        }
        else
        {
            prevTime = currTime;
            currTime = timerTemp.QuadPart;
        }
    
        lua_pushnumber(L, timerTemp.QuadPart);
        return 1;
    }
    
    static int getNanoElapsed(lua_State *L)
    {
        double mNanoSecondsPerCount = 1000000000/(double)FrequencyCountPerSec;
        double elapsedNano = (currTime - prevTime)*mNanoSecondsPerCount;
        lua_pushnumber(L, elapsedNano);
        return 1;
    }
    
    
    int luaopen_HighResolutionTimer (lua_State *L) {
    
        static const luaL_reg mylib [] = 
        {
            {"readHiResTimerFrequency", readHiResTimerFrequency},
            {"storeTime", storeTime},
            {"getNanoElapsed", getNanoElapsed},
            {NULL, NULL}  /* sentinel */
        };
    
        luaL_register(L,"timer",mylib);
    
        return 1;
    }
    

    --

    --

    现在让我们在 lua 脚本 HighResTimer.lua 中加载它。

    注意:我将 HighResTimer.c 编译为共享库 Timer.so

    #!/bin/lua
    ------------------------------------
    ---HighResTimer.lua by Cody Duncan
    ---Wraps the High Resolution Timer Functions in
    ---   Timer.so
    ------------------------------------
    
    package.cpath = "./Timer.so"     --assuming Timer.so is in the same directory
    require "HighResolutionTimer"    --load up the module
    timer.readHiResTimerFrequency(); --stores the tickFrequency
    
    
    --call this before code that is being measured for execution time
    function start()
        timer.storeTime();
    end
    
    --call this after code that is being measured for execution time
    function stop()
        timer.storeTime();
    end
    
    --once the prior two functions have been called, call this to get the 
    --time elapsed between them in nanoseconds
    function getNanosElapsed()
        return timer.getNanoElapsed();
    end
    

    --

    --

    最后,利用计时器 TimerTest.lua。

    #!/bin/lua
    ------------------------------------
    ---TimerTest.lua by Cody Duncan
    ---
    ---HighResTimer.lua and Timer.so must 
    ---   be in the same directory as 
    ---   this script.
    ------------------------------------
    
    require './HighResTimer' 
    
    start();
    for i = 0, 3000000 do io.write("") end --do essentially nothing 3million times.
    stop();
    
    --divide nanoseconds by 1 million to get milliseconds
    executionTime = getNanosElapsed()/1000000; 
    io.write("execution time: ", executionTime, "ms\n");
    

    注意:任何 cmets 都是在将源代码粘贴到帖子编辑器后编写的,因此从技术上讲,这是未经测试的,但希望 cmets 不会混淆任何内容。如果确实如此,我一定会回来并提供修复。

    【讨论】:

    • 有用!如果有人想将此移植到 mac 或 linux,您可以在此处使用高分辨率 C 代码:github.com/tylerneylon/oswrap/blob/master/oswrap_mac/now.c
    • @Tyler:你将如何从 lua 调用它?
    • @SuperJedi224 您必须创建一个 C 包装器,例如 int getHighResTime(lua_State *L) { /* push the time onto the lua stack */ return 1; },添加代码以将 C fns 注册到 Lua,然后使用 Lua C API 将其编译为共享库。这是关于该过程的不错的 pdf:cs.brynmawr.edu/Courses/cs380/fall2011/luar-topics2.pdf
    • 我也会避免清除现有的package.cpath;相反,我会在前面加上package.cpath = "./Timer.so;" .. package.cpath...
    • 在Windows上,你可以从LuaRT调用sys.clock()函数。
    【解决方案6】:

    如果你在 nginx/openresty 中使用 lua,你可以使用ngx.now(),它返回一个毫秒精度的浮点数

    【讨论】:

    • this is wrong github.com/openresty/lua-nginx-module#ngxnow from the docs:“从 nginx 的当前时间戳的纪元返回经过时间的浮点数(以秒为单位)(包括毫秒作为小数部分)缓存时间(与 Lua 的日期库不同,不涉及系统调用)。”
    • 你真没礼貌。你不能肯定我写的是“错误的”。我只提出了一个可能的解决方案(我用于负载测试并且效果很好),并且我链接了文档(因此任何对此感兴趣的人都可以查看详细信息)。
    • 此外,如果您查看源代码,您建议的 ngx.req.start_time 也使用缓存时间(ngx_timeofday)。因此,您可能会得到与 ngx.now 或更早的结果相同的结果。
    • 对不起,我太不礼貌了。我真的很抱歉。但是,如果我理解正确,ngx.now() 返回从请求开始的时间戳+当前脚本运行的时间,直到您实际调用 ngx.now()
    • 不,这是一个纪元时间戳。 ngx.now() 和 ngx.req.start_time() 内部都使用 ngx_timeofday(),这是 nginx 缓存的时间(虽然经常更新)。因此,可能会发生两个函数返回相同的值,或者很可能是彼此接近的不同值。
    【解决方案7】:

    如果您使用的是 OpenResty,那么它通过使用其 ngx.now() 函数提供了内置的毫秒时间精度。虽然如果你想要细粒度的毫秒精度,那么你可能需要先调用 ngx.update_time() 。或者如果你想更进一步......

    如果你使用luajit启用的环境,比如OpenResty,那么你也可以使用ffi来访问基于C的时间函数比如gettimeofday() 例如:(注意:pcall检查是否存在struct timeval 仅在您重复运行它时才需要,例如通过 OpenResty 中的 content_by_lua_file - 没有它您会遇到诸如 attempt to redefine 'timeval' 之类的错误)

    if pcall(ffi.typeof, "struct timeval") then
            -- check if already defined.
    else
            -- undefined! let's define it!
            ffi.cdef[[
               typedef struct timeval {
                    long tv_sec;
                    long tv_usec;
               } timeval;
    
            int gettimeofday(struct timeval* t, void* tzp);
    ]]
    end
    local gettimeofday_struct = ffi.new("struct timeval")
    local function gettimeofday()
            ffi.C.gettimeofday(gettimeofday_struct, nil)
            return tonumber(gettimeofday_struct.tv_sec) * 1000000 + tonumber(gettimeofday_struct.tv_usec)
    end
    

    然后可以从lua中调用新的luagettimeofday()函数来提供微秒级精度的时钟时间。

    确实,可以使用clock_gettime() 采取类似的方法来获得纳秒 精度。

    【讨论】:

    • 最佳答案!
    【解决方案8】:

    凯夫拉是正确的。

    自定义 DLL 的替代方法是 Lua Alien

    【讨论】:

      【解决方案9】:

      在openresty中有一个函数ngx.req.start_time

      来自文档:

      返回一个浮点数,表示当前请求创建时的时间戳(包括毫秒作为小数部分)。

      【讨论】:

      • 不幸的是,在我的情况下,ngx.req.start_time() 返回 0。顺便说一句,与 os.clock() 相同。 Openresty 版本。我正在使用:“openresty/1.13.6.2”
      【解决方案10】:

      您可以使用 C 函数 gettimeofday : http://www.opengroup.org/onlinepubs/000095399/functions/gettimeofday.html

      这里 C 库 'ul_time',函数 sec_usec 驻留在 'time' 全局表中并返回秒,u 秒。将 DLL 复制到 Lua 文件夹,用 require 'ul_time' 打开它。

      http://depositfiles.com/files/3g2fx7dij

      【讨论】:

        【解决方案11】:

        如果您的系统具有可以执行的date 的 GNU 兼容实现,这里有一个以毫秒为单位获取 Epoch 时间的单行方法:

        local function gethammertime()
          return tonumber(assert(assert(io.popen'date +%s%3N'):read'a'))
        end
        

        请注意,assert 调用对于确保读取或打开 date 的任何失败将分别传播错误是必要的。另请注意,这依赖于垃圾收集(或 Lua 5.4 中的终结器)来关闭进程句柄:如果使用 Lua 5.4 之前的版本并且担心资源耗尽,您可能希望将其扩展到三行,如 @987654321 @ 并显式关闭句柄。

        【讨论】:

          【解决方案12】:

          如果您的环境是 Windows 并且您可以访问系统命令,您可以使用 io.popen(command) 获得精确到厘秒的时间:

          local handle = io.popen("echo %time%")
          local result = handle:read("*a")
          handle:close()
          

          结果将包含hh:mm:ss.cc 格式的字符串:(带有尾随换行符)

          "19:56:53.90\n"
          

          注意,它是在本地时区,因此您可能只想提取 .cc 部分并将其与来自 os.time() 的纪元秒数结合起来。

          【讨论】:

          • 我不建议尝试将来自两个单独时间戳的数字组合起来:如果时间在两者之间翻转,这很容易导致跳跃,例如。如果io.popen 调用在 12:34:56.99 运行,os.time 调用在 12:34:57.00 运行(反之亦然)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-25
          • 2017-02-20
          • 1970-01-01
          • 1970-01-01
          • 2017-04-25
          • 1970-01-01
          相关资源
          最近更新 更多