我们有一些代码想要经常从多个线程调用localtime
。 (相关背景:它是一个服务器,你可以要求它的一个东西是作为字符串的本地时间,它希望能够每秒提供100K的请求。)
我们发现在Ubuntu Linux 12.04上,glibc函数localtime_r
(“reentrant localtime”)调用__tz_convert
,still takes a global lock!
(另外,FreeBSD看起来localtime_r
会在每次调用时调用tzset
,因为他们是偏执的,程序可能已经完成了setenv("TZ")
和/或者用户在现在和最后一次调用/etc/localtime
之间下载了localtime_r
的新版本。(这与所描述的情况相反here;似乎glibc调用了{{1} }} on every invocation of localtime
but not localtime_r
,只是让人感到困惑。)
显然,这对表现来说太糟糕了。出于我们的目的,我们希望在服务器开始运行时基本上“快照”当前时区的规则,然后永远使用该快照。因此,我们将继续遵守夏令时规则(因为何时切换到DST的规则将成为快照的一部分),但我们永远不会回到磁盘,接受互斥,或做任何会导致线程的其他事情阻止。 (我们没有尊重tzinfo的下载更新,也没有尊重对tzset
的更改;我们不希望服务器在运行时实际更改时区。)
但是,我无法在网上找到有关如何处理时区规则的任何信息 - 是否存在用于处理时区规则的用户空间API,或者我们是否将被迫重新实现几百行glibc代码来阅读时区数据本身。
我们是否必须重新实现/etc/localtime
下游的所有内容 - 包括__tz_convert
,因为它似乎没有向用户公开?或者我们可以使用一些POSIX接口和/或第三方库来处理时区规则吗?
(我见过http://www.iana.org/time-zones/repository/tz-link.html,但我不确定它是否有用。)
答案 0 :(得分:3)
使用https://github.com/google/cctz
速度快,应该使用非常简单的API做你想做的一切。
特别是,对于等同于localtime
的cctz,请使用cctz::BreakTime()
函数。例如,https://github.com/google/cctz/blob/master/examples/example3.cc
答案 1 :(得分:1)
也许这个free, open-source timezone library符合需要。
它有一个名为LAZY_INIT
的配置标志,完整记录here。默认情况下它处于打开状态,并且在第一次访问每个单独的时区时将调用std::call_once
。但是你可以用:
-DLAZY_INIT=0
然后对std::call_once
的调用消失了。每个时区都从磁盘读取并在首次访问时完全初始化(通过本地静态函数)。从那时起,事情是稳定且无锁的,没有磁盘访问。当然,这会增加前期的初始化时间,但会减少每个时区的“首次访问”时间。
这个库需要C ++ 11/14,因此可能不适合这个原因。它基于(并大量使用)C ++ 11 <chrono>
库。以下是打印出当前本地时间的示例代码:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
auto local = make_zoned(current_zone(), std::chrono::system_clock::now());
std::cout << local << '\n';
}
只为我输出:
2016-04-12 10:13:14.585945 EDT
该库是一种现代化的高性能线程安全设计。它也非常灵活并且完整记录。它的功能远远超出了C localtime
的简单替代品。与C API不同,您可以指定所需的任何IANA timezone,例如:
auto local = make_zoned("Europe/London", std::chrono::system_clock::now());
这给出了伦敦的当前时间:
2016-04-12 15:19:59.035533 BST
请注意,默认情况下,时间戳的精度是std::chrono::system_clock
的精度。如果您更喜欢其他精度,那很容易实现:
using namespace date;
using namespace std::chrono;
auto local = make_zoned("Europe/London", std::chrono::system_clock::now());
std::cout << format("%F %H:%M %Z", local) << '\n';
2016-04-12 15:22 BST
有关详细信息,请参阅docs。