C#处理IIS日志时匿名类型较命名类型性能差异的原因探究
匿名类型 vs 命名类型:IIS日志处理的性能差异疑问
问题背景
我需要处理一个包含28万行数据的IIS日志文件,流程是读取数据存入DataTable后保存。优化代码时发现,使用匿名类型比自定义的IISLog命名类型性能提升明显。
复现代码
核心处理代码
DataTable dataTable = new DataTable(); // 为IISLog的每个属性创建DataTable列 foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(typeof(IISLog))) dataTable.Columns.Add(property.Name, Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType); var items = rows.Select(data => new //IISLog { Date = Convert.ToDateTime(data[0]), Time = data[1], ServerIPAddress = data[2], Method = data[3], URIStem = data[4], URIQuery = data[5], ServerPort = int.Parse(data[6]), UserName = data[7], ClientIPAddress = data[8], UserAgent = data[9], Referrer = data[10], ProtocolStatus = int.Parse(data[11]), ProtocolSubStatus = int.Parse(data[12]), Win32Status = long.Parse(data[13]), TimeTaken = int.Parse(data[14]) }).ToList(); Console.WriteLine("Elapsed: " + stop.ElapsedMilliseconds); foreach (var item in items) { dataTable.Rows.Add(item.Date, item.Time, item.ServerIPAddress, item.Method, item.URIStem, item.URIQuery, item.ServerPort, item.UserName, item.ClientIPAddress, item.UserAgent, item.Referrer, item.ProtocolStatus, item.ProtocolSubStatus, item.Win32Status, item.TimeTaken); } stop.Stop(); Console.WriteLine("Elapsed: " + stop.ElapsedMilliseconds);
IISLog类定义
public class IISLog { public DateTime Date { get; set; } public string Time { get; set; } public string ServerIPAddress { get; set; } public string Method { get; set; } public string URIStem { get; set; } public string URIQuery { get; set; } public int ServerPort { get; set; } public string UserName { get; set; } public string ClientIPAddress { get; set; } public string UserAgent { get; set; } public string Referrer { get; set; } public int ProtocolStatus { get; set; } public int ProtocolSubStatus { get; set; } public long Win32Status { get; set; } public int TimeTaken { get; set; } }
测试结果
- 使用匿名类型:首次计时(转换为列表耗时)1811ms,全部操作完成耗时2203ms
- 使用
IISLog命名类型:首次计时11807ms,全部操作完成耗时21939ms
IIS日志数据格式示例
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken 2024-01-05 04:27:03 1.1.1.1 GET / - 443 - 2.2.2.2 Mozilla/5.0+(compatible;+NetcraftSurveyAgent/1.0;++info@netcraft.com) - 302 0 0 5925
疑问
为什么匿名类型的创建速度快很多,而且遍历它们向DataTable添加值时速度也大幅提升?
补充说明
- 已移除类中的可空int类型;
- 在全新的.NET Framework 4.8独立项目中测试时,两者性能表现一致,说明原项目中存在特殊因素导致该性能差异。
可能的原因分析
既然干净的.NET Framework 4.8项目中两者性能无差异,原项目的性能问题大概率来自以下几个方向:
1. IISLog类的额外特性
- 类可能被标记了
[Serializable]或其他特性,导致实例化时需要额外的序列化逻辑开销; - 属性的get/set方法中隐藏了日志、验证、
INotifyPropertyChanged通知等额外操作,这些逻辑在匿名类型中不存在; - 类被AOP框架(如PostSharp)拦截,实例化或属性访问时注入了额外代码。
2. 反射与类型处理差异
原项目中可能对IISLog类有额外的反射操作,或者TypeDescriptor.GetProperties(typeof(IISLog))的缓存失效,导致每次获取属性时都有额外开销;而匿名类型的属性结构简单,反射处理更快。
3. JIT编译优化差异
原项目中IISLog类可能因为加载时机、依赖关系等原因,JIT编译器没有对其进行充分优化;而匿名类型是编译器动态生成的,结构更紧凑,JIT能更好地优化其实例化和属性访问逻辑。
4. 项目配置或运行环境差异
原项目可能开启了调试选项(如禁用JIT优化)、代码覆盖率工具,或者运行在受限的AppDomain中,导致IISLog类的性能下降;而匿名类型不受这些配置的影响。
内容的提问来源于stack exchange,提问作者Murphybro2
相关产品推荐
相关产品推荐

