3

次のように、ハードコードされた日付と時刻から静的な Unix 時刻を計算する C マクロを誰かが知っている/持っているかどうか疑問に思っています。

time_t t = UNIX_TIMESTAMP(2012, 5, 10, 9, 26, 13);

数値の静的タイムスタンプが必要なので、それを調べています。これはソフトウェア全体で何百回も実行され、毎回異なる日付で実行されます。毎秒何百回も実行されるため、高速であることを確認したいと考えています。何度も日付を変換すると、確実に速度が低下します (つまり、mktime() を呼び出すと、静的な数値をコンパイルするよりも遅くなりますよね?)

[2012 年 11 月 23 日、この段落をより明確にするために更新を行いました]

アップデート

使用されているプロセスに関する詳細情報を使用して、質問を明確にしたいと思います。サーバーがリクエストを受け取ると、リクエストごとに新しいプロセスが開始されます。そのプロセスは常に新しいプラグインで更新され、そのような更新にはデータベースの更新が必要になることがよくあります。これらは一度だけ実行する必要があります。更新が必要かどうかを知るために、Unix の日付を使用したいと考えています (カウンターは時々壊れる可能性が高いため、カウンターを使用するよりも優れています)。

したがって、プラグインは更新シグナルを受信し、on_update() 関数が呼び出されます。そこで私は次のようなことをしたい:

void some_plugin::on_update(time_t last_update)
{
  if(last_update < UNIX_TIMESTAMP(2010, 3, 22, 20, 9, 26)) {
    ...run update...
  }
  if(last_update < UNIX_TIMESTAMP(2012, 5, 10, 9, 26, 13)) {
    ...run update...
  }
  // as many test as required...
}

ご覧のとおり、毎回 UNIX タイムスタンプを計算する必要がある場合、これはプロセスごとに数千の呼び出しを表す可能性があり、1 秒あたり 100 ヒット x 1000 呼び出しを受け取った場合、コンパイラにそれらの数値を計算させることができたときに 100,000 呼び出しを無駄にしましたコンパイル時に 1 回。

このコードはプロセスの実行ごとに 1 回実行されるため、静的変数に値を入れることは重要ではありません。

last_update 変数は、ヒットした Web サイトに応じて変化することに注意してください (データベースから取得されます)。

コード

さて、コードを取得しました:

// helper (Days in February)
#define _SNAP_UNIX_TIMESTAMP_FDAY(year) \
    (((year) % 400) == 0 ? 29LL : \
        (((year) % 100) == 0 ? 28LL : \
            (((year) % 4) == 0 ? 29LL : \
                28LL)))

// helper (Days in the year)
#define _SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) \
    ( \
        /* January */    static_cast<qint64>(day) \
        /* February */ + ((month) >=  2 ? 31LL : 0LL) \
        /* March */    + ((month) >=  3 ? _SNAP_UNIX_TIMESTAMP_FDAY(year) : 0LL) \
        /* April */    + ((month) >=  4 ? 31LL : 0LL) \
        /* May */      + ((month) >=  5 ? 30LL : 0LL) \
        /* June */     + ((month) >=  6 ? 31LL : 0LL) \
        /* July */     + ((month) >=  7 ? 30LL : 0LL) \
        /* August */   + ((month) >=  8 ? 31LL : 0LL) \
        /* September */+ ((month) >=  9 ? 31LL : 0LL) \
        /* October */  + ((month) >= 10 ? 30LL : 0LL) \
        /* November */ + ((month) >= 11 ? 31LL : 0LL) \
        /* December */ + ((month) >= 12 ? 30LL : 0LL) \
    )

#define SNAP_UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
    ( /* time */ static_cast<qint64>(second) \
                + static_cast<qint64>(minute) * 60LL \
                + static_cast<qint64>(hour) * 3600LL \
    + /* year day (month + day) */ (_SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * 86400LL \
    + /* year */ (static_cast<qint64>(year) - 1970LL) * 31536000LL \
                + ((static_cast<qint64>(year) - 1969LL) / 4LL) * 86400LL \
                - ((static_cast<qint64>(year) - 1901LL) / 100LL) * 86400LL \
                + ((static_cast<qint64>(year) - 1601LL) / 400LL) * 86400LL )

警告: これらのマクロを使用して日付を動的に計算しないでください。mktime() より遅いです。ハードコーディングされた日付がある場合、コンパイラはコンパイル時に time_t 値を計算します。コンパイルは遅くなりますが、何度も実行すると速くなります。

4

3 に答える 3

4

式は POSIX にあります。

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

出典: エポックからの XBD 4.15 秒 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15

于 2012-05-10T16:56:30.943 に答える
2

実際には遅すぎると判断した場合は、実用的な簡単な回避策を次に示します。

void myfun() {
  static time_t t = 0;
  if (t == 0)
    t = slow_unix_timestamp(2012, 5, 10, 9, 26, 13);
}

これで、一度だけ計算されます。

于 2012-05-10T16:41:19.267 に答える
1

マクロではありませんが、タイムスタンプは一度だけ初期化され、その後の呼び出しget_timestamp()は単純にメモリ アクセスになります。実行時に初期化ペナルティを支払いますget_timestamp()が、プログラムの早い段階で初期化して、その後の呼び出しを実質的に「無料」にできることを知っているので、最初に呼び出されるだけです。

time_t initialize_timestamp(int y, int m, int d, int h, int min, s)
{
   tm t;
   t.tm_year = y - 1900;
   t.tm_mon = m;
   t.tm.mday = d;
   t.tm_hour = h;
   t.tm_min = min;
   t.tm_sec = s;

   return mktime(&t);
}

time_t get_static_timestamp()
{
   static time_t ts = initialize_timestamp(2012, 5, 10, 9, 26, 13);
   return ts;
}
于 2012-05-10T16:44:48.267 に答える