一次WinForm性能优化

起因

项目中在加载控件,出现闪烁/慢的情况,针对这些问题做出处理,主要是以下两点.

优化自定义控件加载

调整前:
一个大模板有若干小模板,小模板是自定义控件,在小模板上有Label、TextBox等一些控件,在项目加载大模板的时候,因为控件比较多,出现闪烁现象。每次获取新数据的时候,先把小模板移除,再重新创建小模板,然后添加到容器中。

从创建小模版到加载完成,耗时在5s左右,刚开始凭直觉,以为是反射创建小模版,将反射创建改为创建委托.反射耗时1.5s左右,使用委托减少700ms,发现最耗时的操作不是反射.而是将控件添加到窗体上.
//创建委托
private static T GenerateNewObjDelegate<T>(Type type) where T : class
{
    // Create a new, parameterless (specified by Type.EmptyTypes) dynamic method.
    var dynamicMethod = new DynamicMethod("Ctor_" + type.FullName, type, Type.EmptyTypes, true);
    var ilGenerator = dynamicMethod.GetILGenerator();

    // Look up the constructor info for the type we want to create
    var ctorInfo = type.GetConstructor(Type.EmptyTypes);
    if (ctorInfo != null)
    {
        ilGenerator.Emit(OpCodes.Newobj, ctorInfo);
        ilGenerator.Emit(OpCodes.Ret);

        object del = dynamicMethod.CreateDelegate(typeof(T));
        return (T)del;
    }
    return null;
}

使用Profiler工具

使用ants-performance-profile监测项目,发现耗时操作是将小模版添加到窗体中,造成winform界面一直在绘制.
关于.Net Profiler好用的工具:

Redgate家: ANTS Performance Profiler和ANTS Memory Profiler

Jetbrains家: dotTrace和dotMemory

调整后:
在不切换大模板的时候,只是把小模板的数据清空。这样避免了每次创建控件、添加到容器中,然后移除控件。

优化接口服务调用

1. 发现个别模块,在每一次获取数据的时候,有重复调用的情况,移除重复调用的函数。
2. 找出耗时的接口服务,优化Sql查询,比如说常见的缺少索引

总结

  1. 减少控件创建(减少对象创建,就是减少GC回收的次数)
  2. 减少界面绘制(这里是本次最耗时的操作)
  3. 优化接口返回数据的速度
秋风 2019-06-02