我们正在开发一个系统,该系统从tcp/ip流中读取命令,然后执行这些命令。命令由对对象的方法调用组成,该对象也由命令中的id标识。您可以将命令视为元素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.
}
}
}
And somewhere:
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.
}
这段代码必须用一些涉及反射的代码进行初始化:
- 查找可能代表元素的所有类。
- 查找所有具有命令属性的方法等。
- 将所有这些信息存储在一个字典中,包括相应的
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
派生委托。然而,这并不好用,因为我需要能够在Callee
类的任何实例上调用该方法,并且不希望为每个可能的元素*命令保留委托的内存。(将会有许多元素。)只是为了让这一点清楚:
MethodInfo.Invoke
的速度比包括switch
/case
语句的函数调用要慢100倍。这不包括遍历所有类、方法和属性所需的时间,因为这些信息已经准备好了。请不要告诉我其他瓶颈,比如网络情况。它们不是问题。并且它们不是在代码中使用慢速调用的理由。谢谢。
MethodInfo.Invoke
。优化后者可能在性能上没有明显的差异。 - Michael Liu