2017-01-23 3 views
3

AppDomainサンドボックスを作成して、ユーザーが親アプリケーション(VBで記述)から独自のコード(C#またはVB)を実行できるようにしました。私は必須のコードを抽出し、2つの同一のアプリケーションを作成しました。一つはVBのC#です。AppDomainの関数呼び出しでC#がVBよりもずっと早いのはなぜですか?

C#のバージョンが少なくとも60倍高速で動作することに驚きました。

StackOverflowまたはGoogleでこの動作の参照を見つけることができません。 VBがInvoke呼び出しをシリアル化する方法に大きな非効率性がありますか?ここ

は、実行されているタイプであり、Visual Basicのコードである:

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 

ここに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#クラスにも適用されます。さらに、パフォーマンスアナライザは、VBで時間のかなりの部分を占めていたことを、ClaimsIdentityを直列化/直列化解除することが示されました。 C#ではこれの兆候はありません。再び私はこれがVBのクラスに与えられた特別な「装飾」だと推測しています。

ちょっとチェックしてこの余分なものを取り除く方法がないことがあります。

私の唯一の解決策は、別のC#dllにサンドボックスコードを実装することです。

+0

それは理にかなっています - とりわけ、C#には最適化コンパイラがあります(リリースモードではデフォルトである最適化をオンにするとDirectXチームはしばらくベンチマークを行ったと思いますC#が同等のC++の速度の97%で動くことができたことを示しています。 - 速度が重要であれば、間違いなくC#をVB.NETで使用したいと思っています。 – BrainSlugs83

関連する問題