Windows 上 localtime_s() 多线程性能不佳的解决方法
Posted
技术标签:
【中文标题】Windows 上 localtime_s() 多线程性能不佳的解决方法【英文标题】:Workaround for poor multithreaded performance of localtime_s() on Windows 【发布时间】:2016-03-02 14:46:38 【问题描述】:似乎localtime_s()
(相当于标准localtime_r
)在MSVC 中包含一个临界区。
为了比较,这里有 2 个示例应用,一个在循环中执行 localtime_s
,另一个在循环中执行 gmtime_s
。
分析显示从common_localtime_s<__int64>
调用的isindst
内部存在严重的锁争用:
gmtime
没有出现问题:
如果我的进程确实需要本地时间,是否有任何方法可以解决此问题以在多线程环境中获得稳定的localtime_s
性能?
【问题讨论】:
你真的经常调用这个函数以至于它是一个瓶颈吗? 是的,它目前占用了所有已用时间的 70%(64 个 CPU)。 是的,我也遇到过同样的问题。 localtime_s 在多线程环境中很慢。我无法找到解决方案。 锁保护了一些用于缓存DST计算结果的静态变量。你对此无能为力。如果您无法按照建议处理偏移量,您可能必须使用转换的替代实现。请注意,_localtime64_s
也调用了__tzset
,它也需要一些锁,所以我敢打赌,即使你在_isindst
周围工作,它们仍然会咬你一些。
但是localtime
根据输入时间戳计算偏移量。如果输入位于 DST 中,则它会添加 DST 偏移量。没有一种简单的方法可以使用固定偏移量来解决这个问题。
【参考方案1】:
这是一个建议的解决方案:
以最快的速度记录所有时间。当通过 GUI、日志文件或其他方式将它们呈现给用户时,请转换为本地时间。
由于大多数 GUI 和日志输出都是单线程的,这应该消除程序其余部分的争用。
如果程序从不向用户呈现数据,那么只需将其以快速时间格式写出来,然后使用后处理工具对其进行转换或显示。
【讨论】:
确实,我最终在内部使用了gmtime
。但我也通过复制 MS CRT 实现并将所有static
变量设置为thread_local
来实现localtime_lockfree
(当然还要移除锁)。不幸的是,我无法共享生成的代码,因为 MSCRT 许可证禁止共享修改后的源:(【参考方案2】:
由于标准实现使用锁并且没有简单的解决方法,您可能不得不使用不同的实现。我建议尝试以GetTimeZoneInformationForYear
为基础,这将为您提供标准和 DST 时间以及 DST 处于活动状态的日期与 UTC 的偏移量。您还可以选择为您关心的每一年调用一次,并缓存结果以供所有线程使用。
由于gmtime_s
的表现可以接受,我建议您使用它来获取年份。 (注意这是localtime_s
所做的。)减去GetTimeZoneInformationForYear
提供的适当偏差值,然后再次使用gmtime_s
将其拆分为日期组件。
【讨论】:
非常有趣。似乎 MS CRT 中的实现不使用此 API,但始终使用当前时区 (GetTimeZoneInformation
),因此这样做实际上可以更准确。顺便说一句,CRT 实现还支持 TZ
环境变量作为覆盖。以上是关于Windows 上 localtime_s() 多线程性能不佳的解决方法的主要内容,如果未能解决你的问题,请参考以下文章
C语言关于localtime_s()和asctime_s()两个函数的用法。
localtime vs localtime_s 和适当的输入参数
vs2013写c++程序,其中localtime_s函数不接受一个参数怎么解决?!