>  기사  >  백엔드 개발  >  C# 성능 최적화 모범 사례

C# 성능 최적화 모범 사례

黄舟
黄舟원래의
2017-02-25 11:04:451865검색

1. 메모리 누수를 방지하려면 명시적으로 등록된 EvenHandler를 명시적으로 등록 취소해야 합니다.

객체의 이벤트에 멤버 메서드를 등록하면 후자가 A 참조를 보유하게 됩니다. 전자에게. 전자는 이벤트가 로그아웃될 때까지 가비지 수집되지 않습니다.

private void Form1_Load()
{
  ……
  //注册事件
  CommandRemotingContext.CmdChanged += new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);
  ……
}
private void Form1_FromClosed()
{
  ……
  //关闭窗体时及时释放事件
  CommandRemotingContext.CmdChanged -= new ReciverCmdStateChangedEventHandler(this.CommandRemotingContext_CmdChanged);
  ……
}

이벤트로 인한 메모리 누수 문제:

  • 객체 A가 객체 B의 이벤트를 구독합니다

  • 객체 A의 수명 주기가 객체 B의 수명 주기보다 훨씬 깁니다

  • 객체 A가 객체 B를 구독 취소하지 않는 시간

  • 결국 객체 B를 구독 취소할 수 없게 됩니다. 출시 예정


2. 컨트롤에 바인딩된 데이터 소스의 일괄 작업은 자동 새로 고침을 피해야 합니다

  • 클라이언트에서 데이터를 일괄적으로 운영할 경우 컨트롤의 새로 고침 작업으로 인해 불필요한 시간 소모가 발생하게 됩니다

  • 데이터 소스(예: DataTable, Array, List, ObservableCollection 또는 기타 IListSource 등)가 컨트롤에 바인딩된 경우 데이터를 일괄적으로 작업할 때 바인딩 연결을 끊거나 컨트롤 새로 고침을 일시 중단해야 합니다.

    rree

3. 클라이언트와 서버 간의 통신 횟수를 줄입니다.


  • WebService 호출 수가 적을수록 항상 좋은 것은 아닙니다. 전송할 데이터의 양이 많은 경우 여러 호출로 분할하는 것이 좋습니다.

  • 짧은 WebService 호출의 경우 상호 작용 수를 줄이기 위해 최대한 병합해야 합니다.

    this.gcBillList.DataSource = null;
    DataRowCollection rows = this.ds.Tables[0].Rows;
    foreach (DataRow row in rows)
    {
        // DataRow数据操作
    }
    this.gcBillList.DataSource = this.ds.Tables[0].DefaultView;

4. 통신 수를 줄입니다. 클라이언트와 서버 사이

필요하지 않은 경우 루프에서 WebService를 반복적으로 호출하지 마십시오

//多次调用了相同的WS  
txtCompanyName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameByID”,“0001”);  txtCompanyInnerName.Text=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyInnerNameByID”,“0001”);
//合并相邻的WS  
string[] result=SCPubFunctionClient.PublicWSCal<string>(“ForTest”, “GetCompanyNameAndInnerNameByID”,“0001”);
txtCompanyName.Text=result[0];
txtCompanyInnerName.Text= result[1];

5. 박싱 및 언박싱 작업을 피하기 위해 제네릭을 사용합니다(가비지 수집 부담을 줄입니다)

  • 박싱 작업으로 인해 GC 압력이 발생합니다. 컬렉션에서 발생하는 경우 일반 컬렉션을 사용하여 피해야 합니다.

  • 값 유형 컬렉션의 경우 ArrayList 대신 List8742468051c85b06f0a0af9e3e506b5c를 사용하고 Hashtable 대신 Dictionaryb6842da76bed01162354d37c4f2d3464를 사용하세요.

    //循环调用了相同的WS  
    List<Person> persons;
    ……
    foreach(string personID in personIDs)
    {
    	person=HRPubWsClient.getPerson(personID);
    	persons.Add(person);
    }
    //合并WS  
    List<Person> persons;
    ……
    persons =HRPubWsClient.getPersonList(personIDs);

6. 문자열 작업:

C# 문자열 작업 - 가비지 수집 부담 감소
7. 객체 생성을 피하기 위해 상수를 사용하세요

  • 다음 예와 같이 프로그램에 새로운 십진수(0) 코드가 많이 있습니다. , 이로 인해 작은 객체가 자주 생성되고 재활용됩니다. 올바른 접근 방식은 Decimal.Zero 상수를 사용하는 것입니다.

    ArrayList h=new ArrayList();  //不建议
    h.Add(1);
     
    List<object> h = new List<object>();  //不建议
    h.Add(1);
     
    List<int> h = new List<int>();    //建议
    h.Add(1);

8. 불필요한 예외 방지

C# 예외 처리(Catch Throw) IL 분석

9. 여러 요소를 삭제하려면 RemoveAt 대신 RemoveAll을 사용하세요.

  • RemoveAll 메서드를 사용하는 경우 컬렉션(예: List)에서 여러 요소를 한 번에 삭제하려면 List의 내부 배열 크기만 한 번만 조정됩니다. 이는 루프에서 RemoveAt를 호출하는 것보다 훨씬 더 효율적입니다.

    rree

10. C# DataSet 성능 모범 사례

11. 반사 및 동적 바인딩

  • 리플렉션 기술은 컴파일 시 정적 바인딩을 런타임으로 지연되는 동적 바인딩으로 변환하는 기술입니다.

  • C#은 주로 동적으로 객체를 생성하는 5가지 방법을 지원합니다. (시간 소모는 네트워크에서 발생하는데, 이는 제가 실제 측정한 것과는 상당히 다릅니다. 구체적인 테스트는 아래 참조) :

动态创建对象的方式
与Direct Create
1.Type.InvokeMember
慢40倍以上
2.ContructorInfo.Invoke
慢40倍以上
3.Activator.CreateInstance(Type)
慢7倍
4.Activator.CreateInstance(assemblyName, typeName)
慢1000倍以上
5.Assembly.CreateInstance(typeName)
慢40倍以上

  • 应尽量避免使用反射和动态绑定;如必须使用,要遵循以下原则:

1. 使用接口调用方式将动态绑定改造为早期绑定(Direct Call)
2. 使用 Activator.CreateInstance(Type)方式动态创建对象

3. 使用typeof操作符代替GetType调用

小注:

通过循环创建实例记录时间如下:

加载程序集、获取类型在循环外部时间如下(这时不同创建方式消耗时间差距挺大):


代码如下:

 public void TestCreateInstance()
        {
            Stopwatch watch1 = new Stopwatch();
            var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
            Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
            int num = 100000;
            watch1.Start();

            for (int i = 0; i < num; i++)
            {
                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                Activator.CreateInstance(type);
            }
            watch1.Stop();
            label1.Text = "Activator.CreateInstance(Type type)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass");
            }
            watch1.Stop();
            label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                //加载程序集                
                asmb.CreateInstance("TestClass");
            }
            watch1.Stop();
            label3.Text = "assembly.CreateInstance(string typeName)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                object obj = type.InvokeMember(null, BindingFlags.Public |
               BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);
            }
            watch1.Stop();
            label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                ConstructorInfo constructorInfo = type.GetConstructors()[0];
                constructorInfo.Invoke(null);
            }
            watch1.Stop();
            label5.Text = "ContructorInfo.Invoke(object[] parameters)时间:" + watch1.ElapsedMilliseconds + "毫秒";

        }


加载程序集、获取类型在循环内部时间如下(这时不同创建方式消耗时间差距比较小)


代码如下:

 public void TestCreateInstance()
        {
            Stopwatch watch1 = new Stopwatch();
            //var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
            //Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
            int num = 100000;
            watch1.Start();

            for (int i = 0; i < num; i++)
            {
                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                Activator.CreateInstance(type);
            }
            watch1.Stop();
            label1.Text = "Activator.CreateInstance(Type type)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                Activator.CreateInstance("ReflectiveClassLibrary", "ReflectiveClassLibrary.TestClass");
            }
            watch1.Stop();
            label2.Text = "Activator.CreateInstance(string assemblyName,string typeName)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                //加载程序集                
                asmb.CreateInstance("TestClass");
            }
            watch1.Stop();
            label3.Text = "assembly.CreateInstance(string typeName)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                object obj = type.InvokeMember(null, BindingFlags.Public |
               BindingFlags.Instance | BindingFlags.CreateInstance, null, null, null);
            }
            watch1.Stop();
            label4.Text = "Type.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args)时间:" + watch1.ElapsedMilliseconds + "毫秒";

            watch1.Reset();
            watch1.Start();
            for (int i = 0; i < num; i++)
            {
                var asmb = Assembly.LoadFrom("ReflectiveClassLibrary.dll");
                Type type = asmb.GetType("ReflectiveClassLibrary.TestClass");
                ConstructorInfo constructorInfo = type.GetConstructors()[0];
                constructorInfo.Invoke(null);
            }
            watch1.Stop();
            label5.Text = "ContructorInfo.Invoke(object[] parameters)时间:" + watch1.ElapsedMilliseconds + "毫秒";

        }


测试代码如下:

c# 反射测试demo

12、序列化与反序列化

  • 相对于XML、二进制序列化方式,Protobuf效率较高,支持数据量较大

  • protobuf序列化后的大小是json的1/10,xml格式的1/20,是二进制序列化的1/10

 以上就是C# 性能优化最佳实践的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.