gpt4 book ai didi

C#/.NET 动态调用方法的最佳性能方式

转载 作者:行者123 更新时间:2023-11-30 15:52:24 24 4
gpt4 key购买 nike

我们正在开发一个系统,它从 tcp/ip 流中读取命令,然后执行这些命令。命令由对对象的方法调用组成,该对象也由命令的 id int 标识。您可以将命令视为元素 ID(寻址我们要对其调用命令的元素)和命令 ID(寻址应在元素上调用的方法)的信息。此外,我们还有一个问题,即我们需要检查每个命令的某种权限以及应该如何执行该命令。 (是否应该在一个新的Thread中启动等等)

这样的命令调用的示例如下所示:

class Callee
{
public void RegularCall(int command, parameters)
{
switch (command)
{
case 1: // Comand #1
// Check if the permissions allow this command to be called.
// Check if it should be outsourced to the ThreadPool and
// call it accordingly. +Other Checks.
// Finally execute command #1.
break;
case 2: // Comand #2
// Check if the permissions allow that command to be called.
// Check if it should be outsourced to the ThreadPool and
// call it accordingly. +Other Checks.
// Finally execute command #2.
break;
// Many more cases with various combinations of permissions and
// Other flags.
}
}
}

在某处:

static Dictionary<int, Callee> callees = new Dictionary<int, Callee>();

static void CallMethod(int elementId, int commandId, parameters)
{
callees[elementId].RegularCall(commandId, parameters);
}

但是,这种方法有些不雅:

  • 由于一遍又一遍地复制相同的代码,这可能很容易出错。
  • 在某些情况下,很难看出存在哪些命令以及它们的标志是什么。
  • 命令方法充满了可以在方法之外进行的检查。

我的第一个方法是使用反射,看起来是这样的:

class Callee
{
[Command(1)]
[Permissions(0b00111000)]
[UseThreadPool]
public void SpeakingNameForCommand1(parameters)
{
// Code for command #1.
}

[Command(2)]
[Permissions(0b00101011)]
public void SpeakingNameForCommand2(parameters)
{
// Code for command #2.
}

// Again, many more commands.
}

这段代码一定是用一些反射重的代码初始化的:

  1. 找到可能代表一个元素的所有类。
  2. 查找所有具有命令属性等的方法。
  3. 将所有这些信息存储在字典中,包括相应的 MethodInfo

接收命令的调用看起来像这样,其中 CommandInfo 是一个包含调用所需的所有信息的类(MethodInfo,在 ThreadPool 中运行, 权限...):

static Dictionary<int, CommandInfo> commands = new Dictionary<int, CommandInfo>();

static void CallMethod(int elementId, int commandId)
{
CommandInfo ci = commands[commandId];

if (ci.Permissions != EVERYTHING_OK)
throw ...;

if (ci.UseThreadPool)
ThreadPool.Queue...(delegate { ci.MethodInfo.Invoke(callees[elementId], params); });
else
ci.MethodInfo.Invoke(callees[elementId], params);
}

当我对此进行微基准测试时,对 MethodInfo.Invoke 的调用比直接调用慢大约 100 倍。 问题是:是否有一种更快的方法来调用这些“命令”方法,同时又不会失去定义这些命令调用方式的属性的优雅?

我还尝试从 MethodInfo 派生委托(delegate)。但是,这效果不佳,因为我需要能够在 Callee 类的任何实例上调用该方法,并且不想为每个可能的元素的委托(delegate)保留内存 *命令。 (会有很多元素。)

只是为了说明这一点:MethodInfo.Invoke 比包含 switch/case 语句的函数调用慢 100 倍。这不包括遍历所有类、方法和属性的时间,因为这些信息已经准备好了。

请不要告诉我网络等其他瓶颈。他们不是问题。而且他们没有理由在代码中的另一个位置使用慢速调用。谢谢。

最佳答案

您可以使用开放委托(delegate),它比 MethodInfo.Invoke 快大约十倍。您可以像这样从 MethodInfo 创建这样一个 delegate:

delegate void OpenCommandCall(Callee element, parameters);

OpenCommandCall occDelegate = (OpenCommandCall)Delegate.CreateDelegate(typeof(OpenCommandCall), methodInfo));

然后你会像这样调用这个委托(delegate):

occDelegate.Invoke(callee, params);

其中 callee 是您要调用方法的元素,methodInfo 是方法的 MethodInfoparameters 是各种其他参数的占位符。

关于C#/.NET 动态调用方法的最佳性能方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54737635/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com