C# 正则性能

一行正则把接口拖到超时:回溯灾难实录

某个校验接口偶发超时,日志里没有任何异常,就是慢。用采样器跟进去,时间全花在一行看起来人畜无害的正则上:

^(\w+\s?)+$

这行正则想匹配"多个单词"。它的问题在嵌套量词:(\w+\s?)+——外层循环里还套着 \w+,一个词有多种切分方式。匹配失败时,引擎会把所有切分组合都试一遍。对正常输入没感觉,遇到一长串不匹配的字符(比如有人把日志粘进了输入框),回溯次数是指数级的。二十个字符就要试几百万次。

处理流程示意
处理流程示意

修法不复杂,记住两条红线:

.NET 的正则引擎后来加了 NonBacktracking 模式,牺牲一点单次性能换回溯免疫,敏感入口可以考虑。但大多数场景,把正则写对就够了。

事故之后加了条编码规范:正则上线前必须跑一个"恶意输入"用例——50 个字符的不匹配串,必须在毫秒级返回。这一行测试,比事后加超时便宜得多。