Lua-当前时间(以毫秒为单位)


73

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

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


7
我们真的可以在Lua中使用适当的日期/时间库。os.time和os.date通常实际上不会削减它。
尼克·范·布伦特

13
有时候,我觉得整个Lua都不会削减它:P
Nebril

Answers:


35

在标准C lua中,不。除非您愿意自己修改lua解释器以使os.time使用所需的分辨率,否则您将需要安顿下来几秒钟。但是,如果您要编写代码供他人独立运行,而不是像Web应用程序那样可以完全控制环境,那么这可能是不可接受的。

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


6
DLL或.so等,取决于系统... :-)
PhiLho

返回的小数位数是os.clock()多少?

@Kousha的小数位os.clock是几分之一秒;但是,os.clock报告程序执行时间不是实际时间。与Windows系统上os.clock报告的Arcoss平台也是不一致的。real timecpu time
Nifim

60

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

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

这当然增加了依赖性,但是可以很好地用于个人用途(例如,在基准测试脚本中)。


2
请注意,至少有人声称在Windows上此实现的分辨率不够高:lua-users.org/wiki/HiResTimer
Phrogz 2014年

请注意,更新后在我的系统上,此操作停止了。我不得不将其更改为socket = require "socket",否则socket为零。
phemmer

57

如果要进行基准测试,可以使用doc。所示的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))

8
但是,这似乎不是毫秒,而是以1/100 s的精度工作。
schaul

3
如果调用使用线程的C函数,这将无法正常工作。而不是实际花费的时间,它报告所有线程花费的时间,总和为
CiprianTomoiagă2014年

1
此功能以及该os.time功能高度依赖于系统。另请注意,文档指出它返回程序使用的cpu时间,在大多数系统上,它与实际花费的“地球时间”有很大不同。
2016年

3
由于我坚持使用标准Lua,并且它必须是可移植的且封装的(没有外部dll),所以这是我能找到的最佳解决方案。+1
理查德

14

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

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

10

我为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");

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


有用!如果有人想将此移植到Mac或Linux,则可以在此处使用高分辨率的C代码:github.com/tylerneylon/oswrap/blob/master/oswrap_mac/now.c
Tyler

@Tyler:那你将如何从lua打电话呢?
SuperJedi224

@ SuperJedi224您必须创建一个C包装程序,类似int getHighResTime(lua_State *L) { /* push the time onto the lua stack */ return 1; },添加代码以在Lua中注册C fns,然后使用Lua C API作为共享库进行编译。这是有关该过程的不错的pdf文件:cs.brynmawr.edu/Courses/cs380/fall2011/luar-topics2.pdf
Tyler

我也避免消除现有的package.cpath; 相反,我会在前面加上package.cpath = "./Timer.so;" .. package.cpath...
SlySven

4

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


这是不对的github.com/openresty/lua-nginx-module#ngxnow 从文档:“从历元返回一个浮点数,以秒(包括毫秒为小数部分)的经过时间从当前时间标记nginx缓存的时间(与Lua的日期库不同,不涉及系统调用)。”
smartius

你真不礼貌 您不能肯定我写的是“错误的”。我只提出了一个可能的解决方案(用于负载测试,并且效果很好),而且我链接了文档(因此,对此感兴趣的人可以查看详细信息)。
deepskyblue86

此外,如果您查看源,则建议您使用的ngx.req.start_time也使用缓存的时间(ngx_timeofday)。因此,您可能会得到与ngx.now或更早版本相同的结果。
deepskyblue86

对不起,我很不礼貌。我真的很抱歉 但是,如果我正确理解,则ngx.now()返回从请求开始时开始的时间戳+当前脚本运行的时间,直到您实际调用ngx.now()
smartius

不,这是一个时代的时间戳。ngx.now()和ngx.req.start_time()在内部都使用ngx_timeofday(),它是nginx缓存的时间(尽管会经常更新)。因此,可能会发生两个函数都返回相同的值,或者很可能彼此接近的不同值。
deepskyblue86

3

如果您使用的是OpenResty,则可通过使用其ngx.now()函数提供内置的毫秒级时间精度。尽管如果您希望获得毫秒级的精确度,则可能需要先调用ngx.update_time()。或者,如果您想更进一步...

如果您正在使用luajit启用的环境中,如OpenResty,那么你也可以使用FFI访问基于C语言的时间函数,如gettimeofday()如:(注:pcall对于存在检查struct timeval只需要您不断例如,通过运行它content_by_lua_file在OpenResty-没有它,您会遇到错误,例如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

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

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


最好的答案!
mvorisek


2

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

从文档:

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


不幸的是,在我的情况下,ngx.req.start_time()返回0。与os.clock()btw相同。Openresty版本 我正在使用:“ openresty / 1.13.6.2”
esboych '18年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.