Я создал изолированную среду AppDomain, чтобы пользователи могли запускать свой собственный код (C# или VB) из родительского приложения (написанного на VB). Я извлек основной код и создал два одинаковых приложения: один в VB один C#.Почему C# гораздо быстрее при вызове функции в AppDomain, чем VB
Я был поражен, обнаружив, что версия C# работает как минимум в 60 раз быстрее.
Я не могу найти ссылки на это поведение в StackOverflow или Google. Есть ли какая-то большая неэффективность в том, как VB сериализует вызов Invoke
?
Здесь В.Б. код, который является типом выполняется:
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);
}
}
}
Здесь Б. И. Л. (Конструктор + Выполнить):
.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 раз на самом деле недооценка. Она измеряется просто путем вызова функции ExecuteFunction
с:
object[] objects = new object[] { 1.0, 1.0, 1.0 };
в качестве аргументов и варьируя object[0]
, чтобы предотвратить любые оптимизации (100000 петли).
Код, который фактически получает запустить в песочнице очень просто:
public static double StressFactor(double useStress, double stress, double p)
{
return useStress*stress+p;
}
При повторном измерении разности скорости ближе к 41 раз быстрее в C#.
VB и C# почти (но не полностью) идентичны во многих отношениях под капотом. Нет причин ожидать каких-либо существенных нарушений производительности. Я подозреваю, что ваше «идентичное» приложение не так точно, как вы ожидаете. –
Я был поражен, обнаружив, что сообщение не содержит кода. На этом этапе можно только догадываться о том, что вы сделали неправильно ... –
Даже если ваше утверждение верно, вам нужно доказать это здесь, поместив некоторый код и сообщив, где _60 раз быстрее_, и другие могут обсудить об этом. –