/// <summary>
/// Compares different methods of parsing a date/time in the ISO 8601 format.
/// </summary>
[SimpleJob(RuntimeMoniker.Net70)]
[MemoryDiagnoser]
public partial class DateTimeParseExactVsRegex
{
[Params(10, 100, 1_000)]
public int Loops { get; set; }
/// <summary>
/// Parses the input string by using <see cref="DateTime.ParseExact"/>
/// with a custom format.
/// </summary>
[Benchmark(Baseline = true)]
public void ParseExactCustomFormat()
{
DateTime.ParseExact(_serializedDateTime, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
}
private const string _serializedDateTime = "2002-08-11T10:11:12.0000000Z";
/// <summary>
/// Parses the input string by using <see cref="DateTime.ParseExact"/>
/// with a standard format.
/// </summary>
[Benchmark]
public void ParseExactStandardFormat()
{
DateTime.ParseExact(_serializedDateTime, "O",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
}
/// <summary>
/// Parses the input string by using a <see cref="Regex"/>.
/// </summary>
[Benchmark]
public void Regex()
{
Match match = GetRegex().Match(_serializedDateTime);
if (!match.Success)
{
throw new NotImplementedException();
}
int GetInt(string groupName)
{
ReadOnlySpan<char> yearAsString = match.Groups[groupName].ValueSpan;
return int.Parse(yearAsString);
}
int year = GetInt("year"), month = GetInt("month"), day = GetInt("day");
int hour = GetInt("hour"), minute = GetInt("minute"), second = GetInt("second");
int subSecond = GetInt("subsecond");
DateTime _ = new DateTime(year, month, day, hour, minute, second).AddTicks(subSecond);
}
[GeneratedRegex(@"^(?<year>\d{4})\-(?<month>\d{2})\-(?<day>\d{2})T(?<hour>\d{2})\:(?<minute>\d{2})\:(?<second>\d{2})\.(?<subsecond>\d{7})Z$")]
private static partial System.Text.RegularExpressions.Regex GetRegex();
/// <summary>
/// Detects whether the input string matches the date/time format by using a <see cref="Regex"/>.
/// </summary>
[Benchmark]
public void RegexIsMatch() => GetRegex().IsMatch(_serializedDateTime);
}
6条答案
按热度按时间qnakjoqk1#
我的第一个问题是哪一个更有表现力?还是哪个最有可读性?在这种情况下,性能的提高可能是微不足道的,我会投票给最容易维护/阅读的代码。
编辑
找到一个体面的,类似的职位。值得一读
Regex vs Tryparse what is the best in performance
oxf4rvwz2#
一个好的正则表达式应该快得多,并且可能消耗更少的瞬时内存。
但硬币的另一面是:
您非常依赖于一种时间格式,这意味着国际化将是痛苦的,并且您的用户需要接受教育,以正确的格式输入日期。
此外,您将丢失一些日期验证,例如,如何在非闰年中清除2月29日?4月31日
h7appiyu3#
最好的办法是为这两个代码都写一点测试代码,然后运行一个循环来执行一百万次。在不知道输入的情况下,很难回答这个问题(尽管我猜TryParse会更快)。
也就是说,今天的处理器上的时差可能无关紧要。
czq61nw14#
更新:当run in a fiddle TryParse是一个 * 很多 * 快。
我对10000个项目进行了初步测试。看起来Regexp的速度至少是DateTime.Parse的两倍。使用下面的代码自己看看:
jyztefdp5#
在这种情况下,Regex似乎更快,因为Regex只会查找模式,而DateTime parse需要找到模式并从该模式中获取值以创建DateTime对象
scyqe7ek6#
添加基准测试,比较以ISO 8601格式解析日期/时间的不同方法:
底线是:
| 方法|循环|平均值|错误|标准差|比率|比率SD| Gen0|已分配|
| - -----|- -----|- -----|- -----|- -----|- -----|- -----|- -----|- -----|
| ParseExactCustomFormat|十个|277.65纳秒|3.148纳秒|2.791纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|十个|254.07纳秒|0.490 ns| 0.435 ns|零点九二|零点零一|零点零零五|B|
| Regex|十个|423.21纳秒|4.026纳秒|3.766纳秒|一点五二|零点零二|0.0858|小行星1080 B|
| RegexIsMatch|十个|62.19纳秒|0.322纳秒|0.302纳秒|零点二二|零点|- ----|- ----|
| | | | | | | | | |
| ParseExactCustomFormat|一百|255.08纳秒|1.176纳秒|1.042纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|一百|255.18纳秒|1.358纳秒|1.271纳秒|一点|零点零一|零点零零五|B|
| Regex|一百|427.15纳秒|8.149纳秒|7.224纳秒|一点六七|零点零三|0.0858|小行星1080 B|
| RegexIsMatch|一百|88.23纳秒|1.920 ns| 5.508纳秒|零点三二|零点零五|- ----|- ----|
| | | | | | | | | |
| ParseExactCustomFormat|一千|255.65纳秒|1.409纳秒|1.249纳秒|一点|零点|0.0114| B|
| 解析精确标准格式|一千|255.34纳秒|0.689纳秒|0.611 ns|一点|零点|零点零零五|B|
| Regex|一千|437.88纳秒|4.192纳秒|3.273纳秒|一点七一|零点零二|0.0858|小行星1080 B|
| RegexIsMatch|一千|62.69纳秒|0.744纳秒|0.696纳秒|零点二五|零点|- ----|- ----|