admin管理员组

文章数量:1444678

我只用了 3 行 C#:CPU 缓存行就将我的 API 速度提高了一倍

回想一下你上次优化 .NET 应用程序的情景。你可能关注了算法、数据库查询,或者异步模式。但如果我告诉你,仅仅改变数据在内存中的布局,就能让你的应用程序性能翻倍,你会怎么想?这并不是理论上的假设——我们最近在调查高流量 API 的性能问题时,就深刻体会到了这一点。

现代 CPU 的速度非常快!!!但它们大部分时间都在等待。等待什么呢?内存。虽然 CPU 可以在纳秒级的时间内执行指令,但从主内存中获取数据却需要数百个 CPU 周期(这是我们可以控制的部分)。为了弥补这一差距,CPU 使用了缓存层次结构——小而快的内存区域,用于将频繁访问的数据保存在处理核心附近。

问题:一个看似无辜的结构体布局

我们有一个看似无害的结构体,用于处理用户会话数据:

代码语言:javascript代码运行次数:0运行复制
public structSessionData
{
    publicbool IsAuthenticated;    // 1 字节
    publicstring Username;         // 8 字节(引用)
    publicbyte SecurityLevel;      // 1 字节
    publicDateTime LastAccess;     // 8 字节
    publicGuid SessionId;          // 16 字节
}

这个结构体看起来干净且逻辑清晰,对吧?每个字段都按其用途分组。但当我们在负载下分析应用程序时,发现了一个令人惊讶的现象。尽管我们的数据应该完全适合缓存,但 CPU 却花费了大量时间等待内存。

基准测试不会说谎

代码语言:javascript代码运行次数:0运行复制
[MemoryDiagnoser]
publicclassCacheAlignmentBenchmark
{
    privateSessionData[] originalData;
    privateOptimizedSessionData[] alignedData;
    privateconstint ArraySize =10_000;

    [GlobalSetup]
    publicvoidSetup()
    {
        originalData =newSessionData[ArraySize];
        alignedData =newOptimizedSessionData[ArraySize];
       
        for(int i =; i < ArraySize; i++)
        {
            originalData[i]=newSessionData
            {
                IsAuthenticated =(i %==),
                Username =$"user{i}",
                SecurityLevel =(byte)(i %),
                LastAccess = DateTime.UtcNow,
                SessionId = Guid.NewGuid()
            };
        }
    }

    [Benchmark(Baseline = true)]
    publicvoidProcessOriginalLayout()
    {
        for(int i =; i < ArraySize; i++)
        {
            if(originalData[i].IsAuthenticated)
            {
                Process(originalData[i]);
            }
        }
    }

    [Benchmark]
    publicvoidProcessAlignedLayout()
    {
        for(int i =; i < ArraySize; i++)
        {
            if(alignedData[i].IsAuthenticated)
            {
                Process(alignedData[i]);
            }
        }
    }
}

优化后的版本运行速度快了 2.3 倍!不是 2.3%,而是 2.3 倍……

本文标签: 我只用了 3 行 CCPU 缓存行就将我的 API 速度提高了一倍