You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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添加值时速度也大幅提升?

补充说明

  1. 已移除类中的可空int类型;
  2. 在全新的.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 16:14:52