2017-01-23 2 views
3

사용자가 VB에서 작성된 부모 응용 프로그램에서 자신의 코드 (C# 또는 VB)를 실행할 수 있도록 AppDomain 샌드 박스를 만들었습니다. 필자는 필수 코드를 추출하여 두 개의 동일한 응용 프로그램을 만들었습니다. 하나는 VB에서 C#으로 된 응용 프로그램입니다.VB보다 AppDomain의 함수를 호출 할 때 C#이 훨씬 빠릅니다.

나는 C# 버전이 적어도 60 배 더 빠르게 실행된다는 사실에 놀랐다.

StackOverflow 또는 Google에서이 동작에 대한 참조를 찾을 수 없습니다. VB에서 Invoke 호출을 serialize하는 방식에 큰 비 효율성이 있습니까? (생성자 + 실행) 다음

Imports System.Reflection 

Namespace UserCode 
    Namespace Runtime 

    Public Class Execute 
     Inherits MarshalByRefObject 

     Private _MethodInfo As MethodInfo 

     Sub New() 

     _MethodInfo = Nothing 

     End Sub 

     Public Sub SetAssembly(assemblyName As String, functionName As String) 

     _MethodInfo = Nothing 

     If assemblyName <> "" Then 

      Dim assembly As Assembly = AppDomain.CurrentDomain.Load(assemblyName) 
      Dim type As Type = assembly.GetType("CompiledUserCode") 

      _MethodInfo = type.GetMethod(functionName, BindingFlags.Public Or BindingFlags.Static) 

     End If 

     End Sub 

     Public Function ExecuteFunction(args() As Object) As Object 

     Return _MethodInfo.Invoke(Nothing, args) 

     End Function 

    End Class 

    End Namespace 
End Namespace 

는 해당 C 번호 여기

using System; 
using System.Reflection; 


namespace UserCode 
{ 
    public class Execute:MarshalByRefObject 
    { 
     private MethodInfo _MethodInfo; 

    public Execute() 
     { 
     _MethodInfo = null; 

     } 

     public void SetAssembly(string assemblyName ,string functionName) 
     { 
     _MethodInfo = null; 

     if(assemblyName != "") 
     { 

     var assembly = AppDomain.CurrentDomain.Load(assemblyName); 
      var type = assembly.GetType("CompiledUserCode"); 

      _MethodInfo = type.GetMethod(functionName, BindingFlags.Public | BindingFlags.Static); 

     } 
     } 

     public object ExecuteFunction(object[] args) 
     { 
      return _MethodInfo.Invoke(this, args); 
     } 
    } 
} 

인 VB IL은 :

.class public auto ansi UserCode.Runtime.Execute 
    extends [mscorlib]System.MarshalByRefObject 
{ 
    // Fields 
    .field private class [mscorlib]System.Reflection.MethodInfo _MethodInfo 

    // Methods 
    .method public specialname rtspecialname 
     instance void .ctor() cil managed 
    { 
     // Method begins at RVA 0x21c0 
     // Code size 14 (0xe) 
     .maxstack 8 

     IL_0000: ldarg.0 
     IL_0001: call instance void [mscorlib]System.MarshalByRefObject::.ctor() 
     IL_0006: ldarg.0 
     IL_0007: ldnull 
     IL_0008: stfld class [mscorlib]System.Reflection.MethodInfo UserCode.Runtime.Execute::_MethodInfo 
     IL_000d: ret 
    } // end of method Execute::.ctor 

.method public 
    instance object ExecuteFunction (
     object[] args 
    ) cil managed 
{ 
    // Method begins at RVA 0x221c 
    // Code size 14 (0xe) 
    .maxstack 3 
    .locals init (
     [0] object ExecuteFunction 
    ) 

    IL_0000: ldarg.0 
    IL_0001: ldfld class [mscorlib]System.Reflection.MethodInfo UserCode.Runtime.Execute::_MethodInfo 
    IL_0006: ldnull 
    IL_0007: ldarg.1 
    IL_0008: callvirt instance object [mscorlib]System.Reflection.MethodBase::Invoke(object, object[]) 
    IL_000d: ret 
} // end of method Execute::ExecuteFunction 
여기

는 종류가 실행중인 VB 코드

다음은 C# IL입니다.

내가 볼 수
.class public auto ansi beforefieldinit UserCode.Execute 
    extends [mscorlib]System.MarshalByRefObject 
{ 
    // Fields 
    .field private class [mscorlib]System.Reflection.MethodInfo _MethodInfo 

    // Methods 
    .method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
    { 
     // Method begins at RVA 0x275c 
     // Code size 14 (0xe) 
     .maxstack 8 

     IL_0000: ldarg.0 
     IL_0001: call instance void [mscorlib]System.MarshalByRefObject::.ctor() 
     IL_0006: ldarg.0 
     IL_0007: ldnull 
     IL_0008: stfld class [mscorlib]System.Reflection.MethodInfo UserCode.Execute::_MethodInfo 
     IL_000d: ret 
    } // end of method Execute::.ctor 

.method public hidebysig 
     instance object ExecuteFunction (
      object[] args 
     ) cil managed 
    { 
     // Method begins at RVA 0x27b4 
     // Code size 14 (0xe) 
     .maxstack 8 

     IL_0000: ldarg.0 
     IL_0001: ldfld class [mscorlib]System.Reflection.MethodInfo UserCode.Execute::_MethodInfo 
     IL_0006: ldarg.0 
     IL_0007: ldarg.1 
     IL_0008: callvirt instance object [mscorlib]System.Reflection.MethodBase::Invoke(object, object[]) 
     IL_000d: ret 
    } // end of method Execute::ExecuteFunction 

유일한 큰 차이는 다음과 같습니다 현재

.maxstack 3 
     .locals init (
      [0] object ExecuteFunction 
     ) 

내 유일한 옵션은 샌드 박스 코드를 포함하는 별도의 C# 어셈블리를 생성하는 것입니다 C#을 속도를 활용하고자하는 경우. 60 번은 실제로 과소 평가입니다. 인수로

object[] objects = new object[] { 1.0, 1.0, 1.0 }; 

object[0] 변화하는 것은 어떤 최적화 (100000 루프)를 방지하기 위해 : 그것은으로 ExecuteFunction 함수를 호출하여 간단하게 측정한다. 실제로 샌드 박스에서 실행됩니다

의 코드는 매우 간단합니다 : 재 측정 속도의 차이에

public static double StressFactor(double useStress, double stress, double p) 
      { 
      return useStress*stress+p; 
      } 

가까이에 41 배 빠른 C#에서입니다.

+4

VB 및 C#은 여러 가지면에서 거의 동일하지만 완전히 동일하지는 않습니다. 중요한 성능 불일치를 예상 할 이유가 없습니다. 나는 당신의 "동일한"응용 프로그램이 당신이 기대하는만큼 동일하지 않을 것이라고 생각합니다. –

+7

그 게시물에 코드가 포함되어 있지 않다는 사실에 놀랐습니다. 이 시점에서 당신은 당신이 잘못한 것에 대해 추측을 표현할 수 있습니다 ... –

+1

귀하의 진술이 정확하다고하더라도, 여기에 몇 가지 코드를 넣어 증명할 필요가 있으며, _60 배 빠른 곳을 알려주십시오. 다른 사람들이 그것에 대해 토론 할 수 있도록하십시오. –

답변

2

(내가) 몇 시간 동안 조사한 결과, VB가 장면 뒤에서 클래스에주는 추가 '장식'이 원인이라고 생각합니다.

VB에서 간단한 클래스를 체크 아웃하면 해당 C# 클래스 (예 : Binder .../Declared ...)보다 훨씬 많은 속성이 있습니다. 이는 VB에서 인스턴스화 된 C# 클래스에도 적용됩니다. 또한 성능 분석기에서는 ClaimsIdentity를 deserialize/serialize하는 것이 VB에서 좋은 시간을 차지하는 것으로 나타났습니다. C#에서 이것에 대한 서명이 없습니다. 다시 이것은 VB에서 클래스에 주어진 여분의 '장식'이라고 추측합니다.

조금만 확인하면이 여분의 것을 제거 할 방법이 없습니다.

내 유일한 해결책은 별도의 C# dll에 샌드 박스 코드를 구현하는 것입니다.

+0

그게 합리적입니다 - 다른 것들 중에서도 C#은 최적화 컴파일러를 가지고 있습니다 (릴리스 모드의 기본값 인 최적화 기능을 켜면 DirectX 팀에서 잠시 동안 벤치마킹을 한 것 같습니다) C#이 동등한 C++의 속도의 97 %에서 실행될 수 있다는 것을 보여주었습니다. - 따라서 속도가 중요하면 VB.NET을 통해 C#을 사용하고 싶을 것입니다. – BrainSlugs83

관련 문제