减少gettimeofday时间的策略?

时间:2015-07-29 08:57:52

标签: c++ algorithm

我编写了一个统计服务器来计算每天的访问数据,因此我必须每天清除db(memcached)中的数据。

目前,我会调用gettimeofday来获取日期,并将其与缓存日期进行比较,以检查当天是否有相同的日期。

示例代码如下:

void report_visits(...) {
   std::string date = CommonUtil::GetStringDate(); // through gettimeofday
   if (date != static_cached_date_) {
       flush_db_date();
       static_cached_date_ = date;
   }
}

问题是我必须每次调用gettimeofday 客户端报告访问信息。 gettimeofday非常耗时。

针对此问题的任何解决方案?

3 个答案:

答案 0 :(得分:2)

gettimeofday系统调用(现在已过时使用clock_gettime)是要执行的最短系统调用之一。我最后一次测量是在Intel i486上并持续了2us。内核内部版本用于为网络数据包readwritechmod系统调用添加时间戳,以更新文件系统inode中的时间戳等。如果你想测量你在gettimeofday系统调用中花费的时间,你只需要做几个(更多,更好)的调用对,一个接着一个接一个,注释它们之间的时间戳差异并最终获得样本的最小值为适当的值。这将是理想值的良好近似。

如果内核使用它来为文件中的每个read添加时间戳,您可以自由地使用它来为每个服务请求加上时间戳,而不会受到严重的惩罚。

另一件事是,不要使用(如其他响应所示)将gettimeofday结果转换为字符串的例程,因为这确实消耗了更多的资源。您可以比较时间戳(假设它们为t1t2)和

gettimeofday(&t2, NULL);
if (t2.tv_sec - t1.tv_sec > 86400) {  /* 86400 is one day in seconds */
    erase_cache();
    t1 = t2;
} 

或者,如果您希望它每天同时发生

gettimeofday(&t2, NULL);
if (t2.tv_sec / 86400 > t1.tv_sec / 86400) {
    /* tv_sec / 86400 is the number of whole days since 1/1/1970, so
     * if it varies, a change of date has occured */
    erase_cache();
}
t1 = t2; /* now, we made it outside, so we tie to the change of date */

甚至,您可以使用time()系统调用,因为它具有第二个分辨率(并且您不需要处理usecs或struct timeval结构的开销)。

答案 1 :(得分:1)

(这是一个老问题,但缺少一个重要的答案:)

您需要定义TZ环境变量并将其导出到您的程序。如果未设置,则对stat(2)/etc/localtime等的每次通话都会gettimeofday(2) localtime(3) Option Explicit Dim strFile As String Public Sub OneRoutine() 来电。

当然,这些将在不进入磁盘的情况下得到解答,但是呼叫的频率和系统调用的开销足以在某些情况下产生明显的差异。

支持文件:

How to avoid excessive stat(/etc/localtime) calls in strftime() on linux?

https://blog.packagecloud.io/eng/2017/02/21/set-environment-variable-save-thousands-of-system-calls/

答案 2 :(得分:0)

总结:

  1. 正如你所说,检查每秒最多可完成几千次。
  2. 你每天都要刷一次缓存。
  3. 假设你冲洗的确切时间并不重要,可能是几秒钟(甚至可能是几分钟),有一个非常简单/实用的解决方案:

    void report_visits(...)
    {
        static unsigned int counter;
    
        if ((counter++ % 1000) == 0)
        {
            std::string date = CommonUtil::GetStringDate();
            if (date != static_cached_date_)
            {
                flush_db_date();
                static_cached_date_ = date;
            }
        }
    }
    

    每隔N次检查一次report_visits()。在上面的例子中,N是1000。每秒最多可进行几千次检查,您将迟到不到一秒(或一天的0.001%)。

    不要担心counter环绕,它只会在大约20天内发生一次(假设最多几千个检查/秒,32位int),并且不会伤。