0

0

c# 高并发下的 TimeZoneInfo 缓存和性能问题

月夜之吻

月夜之吻

发布时间:2026-01-08 09:19:02

|

185人浏览过

|

来源于php中文网

原创

务必在应用启动时预热 TimeZoneInfo.FindSystemTimeZoneById,避免高并发下因首次解析时区数据库和锁竞争导致 5–20ms/次延迟;ID 大小写敏感,IANA 时区如 "Etc/GMT+8" 需用 CreateCustomTimeZone 构造并预缓存;慎用 TimeZoneInfo.Local,容器中需显式设 TZ 环境变量。

c# 高并发下的 timezoneinfo 缓存和性能问题

TimeZoneInfo.FindSystemTimeZoneById 在高并发下会变慢

TimeZoneInfo.FindSystemTimeZoneById 内部不是纯内存查找,它在首次调用时会触发系统时区数据库的解析(Windows 上读注册表或 ICU 数据,Linux/macOS 依赖 /usr/share/zoneinfo 文件结构),后续调用虽有缓存,但该缓存受内部 ConcurrentDictionary 保护,且存在锁竞争和键规范化开销。实测在 10K+ QPS 场景下,未预热时平均耗时可飙升至 5–20ms/次。

  • 务必在应用启动时主动调用一次 TimeZoneInfo.FindSystemTimeZoneById("UTC") 或常用 ID(如 "China Standard Time")完成初始化
  • 避免在请求处理路径中直接调用 FindSystemTimeZoneById —— 改为从预加载字典中取值:
    private static readonly ConcurrentDictionary _tzCache = new();
    static MyService()
    {
        foreach (var id in new[] { "UTC", "China Standard Time", "Pacific Standard Time" })
        {
            _tzCache[id] = TimeZoneInfo.FindSystemTimeZoneById(id);
        }
    }
  • 注意:ID 是大小写敏感的,"utc" 会抛 TimeZoneNotFoundException

自定义时区(如 Etc/GMT+8)不能用 FindSystemTimeZoneById 直接获取

"Etc/GMT+8" 这类 IANA 时区名在 Windows 上默认不可用,FindSystemTimeZoneById 会直接抛异常;.NET 6+ 虽支持 IANA 数据(需启用 AppContext.SetSwitch("System.Globalization.UseNls", false)),但该开关是进程级的,且切换后会影响所有 DateTimeFormatInfo 行为,不建议 runtime 动态开启。

  • 若必须支持 IANA 时区,改用 TimeZoneInfo.CreateCustomTimeZone 构造固定偏移时区:
    var gmtPlus8 = TimeZoneInfo.CreateCustomTimeZone("GMT+8", TimeSpan.FromHours(8), "GMT+8", "GMT+8");
  • 不要在每次请求中重复创建 —— 同样应预缓存到 ConcurrentDictionarystatic readonly 字段
  • 注意:CreateCustomTimeZone 不支持夏令时,如需 DST,请改用第三方库(如 NodaTime

TimeZoneInfo.ConvertTime 的线程安全性与性能陷阱

TimeZoneInfo.ConvertTime 本身是线程安全的,但它的性能取决于两个因素:目标时区是否已“热”、转换逻辑是否涉及复杂规则(如历史 DST 变更)。对非本地时区做频繁转换(例如日志时间戳转用户本地时间),若未复用 TimeZoneInfo 实例,会反复触发内部时区规则解析。

佳蓝在线销售系统(创业版) 佳蓝在线销售
佳蓝在线销售系统(创业版) 佳蓝在线销售

1、对ASP内核代码进行DLL封装,从而大大提高了用户的访问速度和安全性;2、采用后台生成HTML网页的格式,使程序访问速度得到进一步的提升;3、用户可发展下级会员并在下级购买商品时获得差额利润;4、全新模板选择功能;5、后台增加磁盘绑定功能;6、后台增加库存查询功能;7、后台增加财务统计功能;8、后台面值类型批量设定;9、后台财务曲线报表显示;10、完善订单功能;11、对所有传输的字符串进行安全

下载
  • 禁止这样写:
    var tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
    var local = TimeZoneInfo.ConvertTime(utcTime, tz, TimeZoneInfo.Local); // 每次都 new tz?不,但 FindSystemTimeZoneById 被反复调用就糟了
  • 正确做法是:把 TimeZoneInfo 实例作为字段或参数传入,确保复用
  • 如果转换目标固定(如全站统一转成 "Asia/Shanghai"),直接缓存该实例,别每次都查
  • 极端吞吐场景下,考虑用 DateTimeOffset 替代 —— 若只需偏移量而无需时区名称或 DST 规则,DateTimeOffset 零分配、无查找开销

跨平台部署时 TimeZoneInfo.Local 的行为差异

TimeZoneInfo.Local 在 Linux/macOS 上依赖 TZ 环境变量/etc/localtime 符号链接,在容器中极易为空或指向错误时区(比如 Alpine 镜像默认没设 TZ)。此时 Local 可能回退为 UTC,且首次访问会触发同步锁,造成毛刺。

  • Dockerfile 中显式设置时区:
    ENV TZ=Asia/Shanghai
    RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
  • 代码中不要假设 TimeZoneInfo.Local 总是可用 —— 加一层 fallback:
    private static readonly TimeZoneInfo _appDefaultTz = 
        TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
    public static TimeZoneInfo GetEffectiveTimeZone(TimeZoneInfo? userTz = null) =>
        userTz ?? TimeZoneInfo.Local ?? _appDefaultTz;
  • 注意:TimeZoneInfo.Local 是只读属性,但其内部缓存可能被 ClearCachedData() 清空(极少用,慎调)
缓存策略本身不难,真正容易出问题的是“以为它已经缓存了”——比如漏掉预热、混用大小写 ID、或在容器里忘了配 TZ。这些点一旦在线上高频路径触发,表现就是 CPU 突增 + 请求延迟抖动,排查时容易误判为 GC 或锁竞争。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

476

2023.08.10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

564

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1083

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

775

2023.08.01

windows查看端口被占用的情况
windows查看端口被占用的情况

windows查看端口被占用的情况的方法:1、使用Windows自带的资源监视器;2、使用命令提示符查看端口信息;3、使用任务管理器查看占用端口的进程。本专题为大家提供windows查看端口被占用的情况的相关的文章、下载、课程内容,供大家免费下载体验。

447

2023.08.02

windows无法访问共享电脑
windows无法访问共享电脑

在现代社会中,共享电脑是办公室和家庭的重要组成部分。然而,有时我们可能会遇到Windows无法访问共享电脑的问题。这个问题可能会导致数据无法共享,影响工作和生活的正常进行。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2345

2023.08.08

windows自动更新
windows自动更新

Windows操作系统的自动更新功能可以确保系统及时获取最新的补丁和安全更新,以提高系统的稳定性和安全性。然而,有时候我们可能希望暂时或永久地关闭Windows的自动更新功能。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

773

2023.08.10

windows boot manager
windows boot manager

windows boot manager无法开机的解决方法:1、系统文件损坏,使用Windows安装光盘或USB启动盘进入恢复环境,选择修复计算机,然后选择自动修复;2、引导顺序错误,进入恢复环境,选择命令提示符,输入命令"bootrec /fixboot"和"bootrec /fixmbr",然后重新启动计算机;3、硬件问题,使用硬盘检测工具进行扫描和修复;4、重装操作系统。本专题还提供其他解决

1484

2023.08.28

Golang 分布式缓存与高可用架构
Golang 分布式缓存与高可用架构

本专题系统讲解 Golang 在分布式缓存与高可用系统中的应用,涵盖缓存设计原理、Redis/Etcd集成、数据一致性与过期策略、分布式锁、缓存穿透/雪崩/击穿解决方案,以及高可用架构设计。通过实战案例,帮助开发者掌握 如何使用 Go 构建稳定、高性能的分布式缓存系统,提升大型系统的响应速度与可靠性。

6

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.8万人学习

Git 教程
Git 教程

共21课时 | 2.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号