导读:本期聚焦于小伙伴创作的《C# 高并发场景下使用反射发射(Reflection.Emit)的性能表现如何》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C# 高并发场景下使用反射发射(Reflection.Emit)的性能表现如何》有用,将其分享出去将是对创作者最好的鼓励。

在C#开发中,Reflection.Emit允许开发者在运行时动态生成IL代码并创建类型、方法等,相比普通反射减少了部分元数据查找开销,但在高并发场景下其性能表现仍需结合实际场景分析。

C# 高并发场景下使用反射发射(Reflection.Emit)的性能表现如何

反射发射的基本原理

Reflection.Emit的核心是System.Reflection.Emit命名空间下的类,比如AssemblyBuilderModuleBuilderTypeBuilderMethodBuilder等,开发者可以通过这些类手动编写IL指令,动态生成可执行的代码逻辑。和普通反射相比,它不需要在每次调用时都进行元数据查找和方法绑定,生成后的动态方法可以直接调用。

高并发下的性能测试对比

我们通过一个简单的高并发场景测试,对比直接调用、普通反射调用、反射发射生成的动态方法调用的性能差异。首先定义测试用的基础类:

public class TestService
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

接下来分别实现三种调用方式,并使用多线程模拟高并发场景:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        // 预热,避免JIT编译影响测试结果
        TestDirectCall(1);
        TestNormalReflection(1);
        TestEmitCall(1);

        int concurrencyCount = 100; // 并发线程数
        int invokeCountPerThread = 10000; // 每个线程调用次数

        Console.WriteLine("直接调用性能测试:");
        TestDirectCallConcurrent(concurrencyCount, invokeCountPerThread);

        Console.WriteLine("普通反射调用性能测试:");
        TestNormalReflectionConcurrent(concurrencyCount, invokeCountPerThread);

        Console.WriteLine("反射发射调用性能测试:");
        TestEmitCallConcurrent(concurrencyCount, invokeCountPerThread);
    }

    // 直接调用
    static int DirectCall(TestService service, int a, int b)
    {
        return service.Add(a, b);
    }

    static void TestDirectCall(int count)
    {
        var service = new TestService();
        for (int i = 0; i < count; i++)
        {
            DirectCall(service, i, i + 1);
        }
    }

    static void TestDirectCallConcurrent(int concurrency, int perThreadCount)
    {
        var service = new TestService();
        var tasks = new List<Task>();
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < concurrency; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                for (int j = 0; j < perThreadCount; j++)
                {
                    DirectCall(service, j, j + 1);
                }
            }));
        }
        Task.WaitAll(tasks.ToArray());
        sw.Stop();
        Console.WriteLine($"总调用次数:{concurrency * perThreadCount},耗时:{sw.ElapsedMilliseconds}ms");
    }

    // 普通反射调用
    static MethodInfo _addMethodInfo;
    static object[] _params = new object[2];
    static int NormalReflectionCall(TestService service, int a, int b)
    {
        if (_addMethodInfo == null)
        {
            _addMethodInfo = typeof(TestService).GetMethod("Add");
        }
        _params[0] = a;
        _params[1] = b;
        return (int)_addMethodInfo.Invoke(service, _params);
    }

    static void TestNormalReflection(int count)
    {
        var service = new TestService();
        for (int i = 0; i < count; i++)
        {
            NormalReflectionCall(service, i, i + 1);
        }
    }

    static void TestNormalReflectionConcurrent(int concurrency, int perThreadCount)
    {
        var service = new TestService();
        var tasks = new List<Task>();
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < concurrency; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                for (int j = 0; j < perThreadCount; j++)
                {
                    NormalReflectionCall(service, j, j + 1);
                }
            }));
        }
        Task.WaitAll(tasks.ToArray());
        sw.Stop();
        Console.WriteLine($"总调用次数:{concurrency * perThreadCount},耗时:{sw.ElapsedMilliseconds}ms");
    }

    // 反射发射生成动态方法
    static Func<TestService, int, int, int> _emitFunc;
    static Func<TestService, int, int, int> GenerateEmitFunc()
    {
        var method = typeof(TestService).GetMethod("Add");
        var dynamicMethod = new DynamicMethod("AddProxy", typeof(int), new[] { typeof(TestService), typeof(int), typeof(int) });
        var ilGenerator = dynamicMethod.GetILGenerator();
        // 加载第一个参数(TestService实例)
        ilGenerator.Emit(OpCodes.Ldarg_0);
        // 加载第二个参数a
        ilGenerator.Emit(OpCodes.Ldarg_1);
        // 加载第三个参数b
        ilGenerator.Emit(OpCodes.Ldarg_2);
        // 调用TestService的Add方法
        ilGenerator.Emit(OpCodes.Callvirt, method);
        // 返回结果
        ilGenerator.Emit(OpCodes.Ret);
        return (Func<TestService, int, int, int>)dynamicMethod.CreateDelegate(typeof(Func<TestService, int, int, int>));
    }

    static int EmitCall(TestService service, int a, int b)
    {
        if (_emitFunc == null)
        {
            _emitFunc = GenerateEmitFunc();
        }
        return _emitFunc(service, a, b);
    }

    static void TestEmitCall(int count)
    {
        var service = new TestService();
        for (int i = 0; i < count; i++)
        {
            EmitCall(service, i, i + 1);
        }
    }

    static void TestEmitCallConcurrent(int concurrency, int perThreadCount)
    {
        var service = new TestService();
        var tasks = new List<Task>();
        var sw = System.Diagnostics.Stopwatch.StartNew();
        for (int i = 0; i < concurrency; i++)
        {
            tasks.Add(Task.Run(() =>
            {
                for (int j = 0; j < perThreadCount; j++)
                {
                    EmitCall(service, j, j + 1);
                }
            }));
        }
        Task.WaitAll(tasks.ToArray());
        sw.Stop();
        Console.WriteLine($"总调用次数:{concurrency * perThreadCount},耗时:{sw.ElapsedMilliseconds}ms");
    }
}

测试结果分析

在多次测试后,我们可以得到大致的性能排序:直接调用耗时最短,其次是反射发射生成的动态方法调用,普通反射调用耗时最长。在高并发场景下,反射发射的优势主要体现在以下几个方面:

  • 动态方法生成后会被缓存,后续调用不需要重复生成,减少了IL生成的开销
  • 避免了普通反射每次调用时的元数据查找和方法绑定开销
  • 生成的动态方法和直接调用的性能差距在高并发下会被进一步缩小,因为JIT编译后的执行效率接近直接调用

但反射发射也存在性能瓶颈:

  • 首次生成动态方法时需要编写IL指令、创建委托,这个过程有一定的开销,不适合频繁动态生成不同的方法
  • 如果高并发下频繁创建新的动态方法,会导致内存占用上升,甚至触发GC,反而影响性能
  • 动态方法的缓存如果处理不当,会出现线程安全问题,导致重复生成或者缓存失效

高并发下使用反射发射的优化建议

如果需要在高并发场景下使用Reflection.Emit,可以参考以下优化方案:

1. 缓存生成的动态委托

将生成的动态方法对应的委托缓存起来,避免重复生成,比如使用ConcurrentDictionary做线程安全的缓存:

using System.Collections.Concurrent;

public static class EmitDelegateCache
{
    private static readonly ConcurrentDictionary<string, object> _cache = new ConcurrentDictionary<string, object>();

    public static Func<TestService, int, int, int> GetAddDelegate()
    {
        return (Func<TestService, int, int, int>)_cache.GetOrAdd("TestService_Add", key =>
        {
            var method = typeof(TestService).GetMethod("Add");
            var dynamicMethod = new DynamicMethod("AddProxy", typeof(int), new[] { typeof(TestService), typeof(int), typeof(int) });
            var ilGenerator = dynamicMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Ldarg_0);
            ilGenerator.Emit(OpCodes.Ldarg_1);
            ilGenerator.Emit(OpCodes.Ldarg_2);
            ilGenerator.Emit(OpCodes.Callvirt, method);
            ilGenerator.Emit(OpCodes.Ret);
            return dynamicMethod.CreateDelegate(typeof(Func<TestService, int, int, int>));
        });
    }
}

2. 避免频繁动态生成不同类型或方法

反射发射适合场景是动态生成的逻辑相对固定,只需要生成一次就可以重复使用的情况,如果需要频繁生成不同的动态逻辑,建议评估是否可以使用其他方式替代,比如表达式树或者提前生成代码。

3. 注意动态程序集的生命周期

如果使用AssemblyBuilder创建动态程序集,要注意程序集的生命周期,避免不必要的内存占用,优先使用DynamicMethod,它的轻量级特性更适合高并发场景下的临时动态逻辑生成。

总结

在高并发场景下,Reflection.Emit的性能表现远优于普通反射,接近直接调用的性能,前提是做好动态委托的缓存,避免频繁生成动态方法。如果动态生成的逻辑是固定可复用的,反射发射是高并发下替代普通反射的优质选择,否则需要结合具体场景评估是否适用,避免出现性能反效果。

C#Reflection_Emit高并发性能优化修改时间:2026-07-12 09:12:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。