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#でに近いです。
VBとC#はボンネットの下では多くの点でほぼ同じですが、完全ではありません。重大なパフォーマンスのばらつきが予想される理由はありません。私はあなたの "同一の"アプリケーションが期待どおりに同じではないと思われるでしょう。 –
私は郵便にコードが含まれていないことに驚きました。この時点で、あなたはあなたが間違ったことを推測することしかできません... –
あなたの声明が正しい場合であっても、ここにいくつかのコードを書いてそれを証明し、_60倍早く来たことを伝える必要があります。 –