什么是快,上线开关或ELSEIF的类型? [英] What is quicker, switch on string or elseif on type?

查看:142
本文介绍了什么是快,上线开关或ELSEIF的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以说我有一个识别code路径的选择采取了字符串比较的基础上,否则iffing类型上:

Lets say I have the option of identifying a code path to take on the basis of a string comparison or else iffing the type:

这是更快,为什么?

switch(childNode.Name)
{
    case "Bob":
      break;
    case "Jill":
      break;
    case "Marko":
      break;
}

if(childNode is Bob)
{
}
elseif(childNode is Jill)
{
}
else if(childNode is Marko)
{
}

更新:的主要原因请问这是因为开关语句是perculiar大约为案例最重要的。例如,它不会允许你使用的变量,只有那些无法移动到主组件常量。我以为它有这种限制,由于一些时髦的东西它在做什么。如果只翻译成elseifs(作为一个海报注释),那么,我们为什么不可以在case语句变量?

Update: The main reason I ask this is because the switch statement is perculiar about what counts as a case. For example it wont allow you to use variables, only constants which get moved to the main assembly. I assumed it had this restriction due to some funky stuff it was doing. If it is only translating to elseifs (as one poster commented) then why are we not allowed variables in case statements?

警告:我-优化后。这种方法被称为的许多的在应用程序的一部分缓慢倍。

Caveat: I am post-optimising. This method is called many times in a slow part of the app.

推荐答案

格雷格的分析结果是伟大的,他所涵盖的具体方案,但有趣的是,不同方法的相对成本考虑许多不同的因素,包括当发生显着变化被比较的类型数目,相对频率和在基础数据的任何模式。

Greg's profile results are great for the exact scenario he covered, but interestingly, the relative costs of the different methods change dramatically when considering a number of different factors including the number of types being compared, and the relative frequency and any patterns in the underlying data.

简单的答案是,没有人能告诉你什么性能上的差异将是在特定的情况下,你需要衡量不同的方式自己在自己的系统中得到一个准确的答案的性能。

The simple answer is that nobody can tell you what the performance difference is going to be in your specific scenario, you will need to measure the performance in different ways yourself in your own system to get an accurate answer.

在的if / else链是少数类型比较的有效途径,或者如果你能可靠地predict这几种类型的要占大多数,你看到的那些的。用该方法的潜在问题是,作为类型数量的增加,必须执行的增加以及比较的数量。
如果我执行以下命令:

The If/Else chain is an effective approach for a small number of type comparisons, or if you can reliably predict which few types are going to make up the majority of the ones that you see. The potential problem with the approach is that as the number of types increases, the number of comparisons that must be executed increases as well. if I execute the following:


int value = 25124;
if(value == 0) ...
else if (value == 1) ...
else if (value == 2) ...
...
else if (value == 25124) ... 

每个previous的

如果输入了正确的块之前条件必须进行评估。另一方面

each of the previous if conditions must be evaluated before the correct block is entered. On the other hand


switch(value) {
 case 0:...break;
 case 1:...break;
 case 2:...break;
 ...
 case 25124:...break;
}

将执行一个简单的跳转至code正确的位。

will perform one simple jump to the correct bit of code.

那里得到你的例子更复杂的是,你的其他方法使用对字符串的开关,而不是它得到一个稍微复杂一点的整数。在一个较低的水平,串不能以同样的方式可以这么C#编译器做了一些魔法整数值,使这项工作给你接通。

Where it gets more complicated in your example is that your other method uses a switch on strings rather than integers which gets a little more complicated. At a low level, strings can't be switched on in the same way that integer values can so the C# compiler does some magic to make this work for you.

如果switch语句是足够小(其中编译器做什么它认为是最好的自动)的字符串转换产生code,它是同为的if / else链。

If the switch statement is "small enough" (where the compiler does what it thinks is best automatically) switching on strings generates code that is the same as an if/else chain.


switch(someString) {
 case "Foo": DoFoo(); break;
 case "Bar": DoBar(); break;
 default: DoOther; break;
}
is the same as:
if(someString == "Foo") {
 DoFoo();
}
else if(someString == "Bar") {
 DoBar();
}
else {
 DoOther();
}

在字典中的项目列表中得到足够大的编译器会自动创建一个从交换机的字符串映射到一个整数索引,然后基于该指数的开关内部的字典。

Once the list of items in the dictionary gets "big enough" the compiler will automatically create an internal dictionary that maps from the strings in the switch to an integer index and then a switch based on that index.

这看起来是这样的(试想一下,更多的条目比我要费心型)

It looks something like this (Just imagine more entries than I am going to bother to type)

一个静态字段是在与包含类型字典&LT的switch语句中的类相关联的隐藏的位置定义的;并给予重整名称

A static field is defined in a "hidden" location that is associated with the class containing the switch statement of type Dictionary<string, int> and given a mangled name


//Make sure the dictionary is loaded
if(theDictionary == null) { 
 //This is simplified for clarity, the actual implementation is more complex 
 // in order to ensure thread safety
 theDictionary = new Dictionary<string,int>();
 theDictionary["Foo"] = 0;
 theDictionary["Bar"] = 1;
}
int switchIndex;
if(theDictionary.TryGetValue(someString, out switchIndex)) {
 switch(switchIndex) {
  case 0: DoFoo(); break;
  case 1: DoBar(); break;
 }
}
else {
 DoOther();
}

在一些快速的测试,我只是跑时,如果/其他方法大约是3倍的速度为3种不同类型的开关(其中类型是随机分布)。在25种开关,在50种更快由小余量(16%)的开关比快一倍以上。

In some quick tests that I just ran, the If/Else method is about 3x as fast as the switch for 3 different types (where the types are randomly distributed). At 25 types the switch is faster by a small margin (16%) at 50 types the switch is more than twice as fast.

如果您打算在大量的类型进行切换,我建议第三位的方法:

If you are going to be switching on a large number of types, I would suggest a 3rd method:


 private delegate void NodeHandler(ChildNode node);

 static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher =
      CreateSwitcher();
 private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher() {
  Dictionary<RuntimeTypeHandle, NodeHandler> ret = 
    new Dictionary<RuntimeTypeHandle, NodeHandler>();

  ret[typeof(Bob).TypeHandle] = HandleBob;
  ret[typeof(Jill).TypeHandle] = HandleJill;
  ret[typeof(Marko).TypeHandle] = HandleMarko;
  return ret;
 }

 void HandleChildNode(ChildNode node) {
  NodeHandler handler;
  if(TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler)) {
   handler(node);
  }
  else {
   //Unexpected type...
  }
 }
}

这是类似于特德埃利奥特建议,但运行时类型的使用处理,而不是完全类型的对象避免通过反射加载类型对象的开销。

This is similar to what Ted Elliot suggested, but the usage of runtime type handles instead of full type objects avoids the overhead of loading the type object through reflection.

下面是我的机器上一些快速时序:

Here are some quick timings on my machine:


Testing 3 iterations with 5,000,000 data elements (mode=Random) and 5 types
Method                Time    % of optimal
If/Else               179.67  100.00
TypeHandleDictionary  321.33  178.85
TypeDictionary        377.67  210.20
Switch                492.67  274.21

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 10 types
Method                Time    % of optimal
If/Else               271.33  100.00
TypeHandleDictionary  312.00  114.99
TypeDictionary        374.33  137.96
Switch                490.33  180.71

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 15 types
Method                Time    % of optimal
TypeHandleDictionary  312.00  100.00
If/Else               369.00  118.27
TypeDictionary        371.67  119.12
Switch                491.67  157.59

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 20 types
Method                Time    % of optimal
TypeHandleDictionary  335.33  100.00
TypeDictionary        373.00  111.23
If/Else               462.67  137.97
Switch                490.33  146.22

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 25 types
Method                Time    % of optimal
TypeHandleDictionary  319.33  100.00
TypeDictionary        371.00  116.18
Switch                483.00  151.25
If/Else               562.00  175.99

Testing 3 iterations with 5,000,000 data elements (mode=Random) and 50 types
Method                Time      % of optimal
TypeHandleDictionary  319.67    100.00
TypeDictionary        376.67    117.83
Switch                453.33    141.81
If/Else               1,032.67  323.04

在我的机器上至少型手柄字典方法击败所有其他的任何东西的超过15种不同类型的分布时,
用作输入到该方法的类型是随机的。

On my machine at least, the type handle dictionary approach beats all of the others for anything over 15 different types when the distribution of the types used as input to the method is random.

如果在另一方面,该输入被完全被首先检查在如果/其他链,其方法是类型组成的的更快

If on the other hand, the input is composed entirely of the type that is checked first in the if/else chain that method is much faster:


Testing 3 iterations with 5,000,000 data elements (mode=UniformFirst) and 50 types
Method                Time    % of optimal
If/Else               39.00   100.00
TypeHandleDictionary  317.33  813.68
TypeDictionary        396.00  1,015.38
Switch                403.00  1,033.33

相反,如果输入的是总是在如果/其他链的最后一件事,它具有相反的效果:

Conversely, if the input is always the last thing in the if/else chain, it has the opposite effect:


Testing 3 iterations with 5,000,000 data elements (mode=UniformLast) and 50 types
Method                Time      % of optimal
TypeHandleDictionary  317.67    100.00
Switch                354.33    111.54
TypeDictionary        377.67    118.89
If/Else               1,907.67  600.52

如果你可以让你输入一些假设,你可能会从您执行的if / else检查的几类是最常见的一种混合的方法最好的性能,然后回落到一个字典驱动的方法,如果那些失败。

If you can make some assumptions about your input, you might get the best performance from a hybrid approach where you perform if/else checks for the few types that are most common, and then fall back to a dictionary-driven approach if those fail.

这篇关于什么是快,上线开关或ELSEIF的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆