我可以比较的IL代码,以确定哪些技术是更快,更好? [英] Can I compare IL code to determine which technique is faster or better?

查看:198
本文介绍了我可以比较的IL代码,以确定哪些技术是更快,更好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景



这个问题 让我思考着什么。最近,因为我一直在寻找的 LINQ垫 的IL功能,我一直比较IL代码的两种方法有同样的问题为确定,这是最好的。



使用链接到上面的问题,有关转换的阵列,我生成IL代码这两个答案:

  VAR ARR =新的String [] {1,2,3,4 }; 
VAR的结果= Array.ConvertAll(ARR,S = GT; Int32.Parse(S));



制作:

  IL_0001:ldc.i4.4 
IL_0002:newarr System.String
IL_0007:stloc.2
IL_0008:ldloc.2
IL_0009:ldc.i4。 0
IL_000A:ldstr1
IL_000F:stelem.ref
IL_0010:ldloc.2
IL_0011:ldc.i4.1
IL_0012:ldstr2
IL_0017:stelem.ref
IL_0018:ldloc.2
IL_0019:ldc.i4.2
IL_001A:ldstr3
IL_001F:stelem.ref
IL_0020:ldloc.2
IL_0021:ldc.i4.3
IL_0022:ldstr4
IL_0027:stelem.ref
IL_0028:ldloc.2
IL_0029:stloc.0
IL_002A:ldloc.0
IL_002B:ldsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_0030:brtrue.s IL_0045
IL_0032:ldnull
IL_0033:ldftn b__0
IL_0039:newobj System.Converter< System.String,System.Int32> ..男星
IL_003E:stsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_0043:BR .S IL_0045
IL_0045:ldsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_004A:拨打System.Array.ConvertAll
IL_004F:stloc.1

b__0:
IL_0000:ldarg.0
IL_0001:拨打System.Int32.Parse
IL_0006:stloc.0
IL_0007:br.s IL_0009
IL_0009:ldloc.0
IL_000A:RET

和对方回答:

  VAR ARR =新的String [] {1,2,3,4}; 
变种结果= arr.Select(S => int.Parse(S))ToArray的();



制作:

  IL_0001:ldc.i4.4 
IL_0002:newarr System.String
IL_0007:stloc.2
IL_0008:ldloc.2
IL_0009:ldc.i4。 0
IL_000A:ldstr1
IL_000F:stelem.ref
IL_0010:ldloc.2
IL_0011:ldc.i4.1
IL_0012:ldstr2
IL_0017:stelem.ref
IL_0018:ldloc.2
IL_0019:ldc.i4.2
IL_001A:ldstr3
IL_001F:stelem.ref
IL_0020:ldloc.2
IL_0021:ldc.i4.3
IL_0022:ldstr4
IL_0027:stelem.ref
IL_0028:ldloc.2
IL_0029:stloc.0
IL_002A:ldloc.0
IL_002B:ldsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_0030:brtrue.s IL_0045
IL_0032:ldnull
IL_0033:ldftn b__0
IL_0039:newobj System.Func< System.String,System.Int32> ..男星
IL_003E:stsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_0043:BR .S IL_0045
IL_0045:ldsfld UserQuery.CS $<> 9__CachedAnonymousMethodDelegate1
IL_004A:拨打System.Linq.Enumerable.Select
IL_004F:拨打System.Linq.Enumerable.ToArray
IL_0054:stloc.1

b__0:
IL_0000:ldarg.0
IL_0001:拨打System.Int32.Parse
IL_0006:stloc.0
IL_0007:br.s IL_0009
IL_0009:ldloc.0
IL_000A:RET

看着这一点,我可以告诉的是,后一种选择




  • 需要1额外的行

  • 使用LINQ时,第一个答案并不

  • 通过IL_0039创建诠释的不同。



问题




  • 对于这个具体的例子,是我的假设是否正确?

  • 在一般情况下,我应该怎么去通过IL代码比较两个方案?

  • 在一般情况下,确实用更少的IL LOC的解决方案意味着,这将是更快,使用较少的内存?

  • 正如标题所说,我可以比较的IL代码,以确定哪些技术是更快,更好?



FWIW,我不罕见的,而当一些讨论出现在当中的开发工作,做到这一点的时候,只是每一次。有人会说:哦,这是更有效,我们就会把它扔进linqpad检查出的IL代码。此外FWIW,我几乎总是由得到它得到它高效/快捷方式工作之前遵守。正是这样的人不认为我不断地比较什么,我开发的IL代码:)


解决方案


  • 对于这个具体的例子,是我的假设是否正确?

  • 在一般情况下,我应该如何去通过IL代码比较两个方案?

  • 在一般情况下,确实用更少的IL LOC的解决方案意味着,这将是更快,使用较少的内存?

  • 正如标题所说,我可以比较IL代码确定哪些技术是更快,更好?




1)你的假设发生的事情是正确的。



2)你需要了解的IL代码,以确定这是更好



3)号这意味着需要较少的指令来运行。然而,这些单个指令可能会使用更多的内存或更低。例如,你被引用指令,在一种情况下,是创建函数求委托,并在另一种是创建一个转换器对象。没有更多的信息,这是很难判断其中的两件事情是比较贵的。



4)是的,没有......



的问题是,IL代码会告诉你发生了什么,但它确实在IL嵌套调用,都将是很大的性能驱动程序。如果IL代码是无处不在做简单的操作,在一般时间越短越好(尽管个别的IL操作可以在速度变化,本身)。当代码调用到其他类型,比如你的方法或构造,这成为不可能从这个独自诉说。 IL的一行可以在一种情况下需要更长的时间在另一种情况下(他们正在做的,其中简单的操作)(如果它调用一个昂贵的方法,例如)大于50



在上面的情况下,例如,前20个操作是非常非常快的,wheras过去几年采取几乎所有的可执行文件的时间。


Background

This question got me thinking about something. Lately, since I've been looking at linq pad's IL functionality, I've been comparing the IL code of two approaches to the same problem to "determine" which is best.

Using the question linked to above, about converting an array, I generated the IL code for the two answers:

var arr = new string[] { "1", "2", "3", "4" };
var result = Array.ConvertAll(arr, s => Int32.Parse(s));

produced:

IL_0001:  ldc.i4.4    
IL_0002:  newarr      System.String
IL_0007:  stloc.2     
IL_0008:  ldloc.2     
IL_0009:  ldc.i4.0    
IL_000A:  ldstr       "1"
IL_000F:  stelem.ref  
IL_0010:  ldloc.2     
IL_0011:  ldc.i4.1    
IL_0012:  ldstr       "2"
IL_0017:  stelem.ref  
IL_0018:  ldloc.2     
IL_0019:  ldc.i4.2    
IL_001A:  ldstr       "3"
IL_001F:  stelem.ref  
IL_0020:  ldloc.2     
IL_0021:  ldc.i4.3    
IL_0022:  ldstr       "4"
IL_0027:  stelem.ref  
IL_0028:  ldloc.2     
IL_0029:  stloc.0     
IL_002A:  ldloc.0     
IL_002B:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0030:  brtrue.s    IL_0045
IL_0032:  ldnull      
IL_0033:  ldftn       b__0
IL_0039:  newobj      System.Converter<System.String,System.Int32>..ctor
IL_003E:  stsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0043:  br.s        IL_0045
IL_0045:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_004A:  call        System.Array.ConvertAll
IL_004F:  stloc.1     

b__0:
IL_0000:  ldarg.0     
IL_0001:  call        System.Int32.Parse
IL_0006:  stloc.0     
IL_0007:  br.s        IL_0009
IL_0009:  ldloc.0     
IL_000A:  ret

and the other answer:

var arr = new string[] { "1", "2", "3", "4" };
var result = arr.Select(s => int.Parse(s)).ToArray();

produced:

IL_0001:  ldc.i4.4    
IL_0002:  newarr      System.String
IL_0007:  stloc.2     
IL_0008:  ldloc.2     
IL_0009:  ldc.i4.0    
IL_000A:  ldstr       "1"
IL_000F:  stelem.ref  
IL_0010:  ldloc.2     
IL_0011:  ldc.i4.1    
IL_0012:  ldstr       "2"
IL_0017:  stelem.ref  
IL_0018:  ldloc.2     
IL_0019:  ldc.i4.2    
IL_001A:  ldstr       "3"
IL_001F:  stelem.ref  
IL_0020:  ldloc.2     
IL_0021:  ldc.i4.3    
IL_0022:  ldstr       "4"
IL_0027:  stelem.ref  
IL_0028:  ldloc.2     
IL_0029:  stloc.0     
IL_002A:  ldloc.0     
IL_002B:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0030:  brtrue.s    IL_0045
IL_0032:  ldnull      
IL_0033:  ldftn       b__0
IL_0039:  newobj      System.Func<System.String,System.Int32>..ctor
IL_003E:  stsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0043:  br.s        IL_0045
IL_0045:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_004A:  call        System.Linq.Enumerable.Select
IL_004F:  call        System.Linq.Enumerable.ToArray
IL_0054:  stloc.1     

b__0:
IL_0000:  ldarg.0     
IL_0001:  call        System.Int32.Parse
IL_0006:  stloc.0     
IL_0007:  br.s        IL_0009
IL_0009:  ldloc.0     
IL_000A:  ret

Looking at this, all I can tell is that the latter option

  • takes 1 extra line
  • uses linq when the 1st answer doesn't
  • creates the Int's differently via IL_0039.

Questions

  • For this specific example, are my assumptions correct?
  • In general, how should I go about comparing two solutions via IL code?
  • In general, does a solution with fewer IL LOC mean that it will be faster or use less memory?
  • As the title says, Can I compare IL code to determine which technique is faster or better?

FWIW, I don't do this often, just every once in a rare while when some discussion comes up amongst developers at work. Someone will say "oh this is more efficient" and we'll throw it into linqpad to check out the IL code. Also FWIW, I almost always abide by the getting it working before getting it efficient/fast approach. Just so people don't think I'm constantly comparing IL code of what I'm developing :)

解决方案

  • For this specific example, are my assumptions correct?
  • In general, how should I go about comparing two solutions via IL code?
  • In general, does a solution with fewer IL LOC mean that it will be faster or use less memory?
  • As the title says, Can I compare IL code to determine which technique is faster or better?

1) Your assumptions are correct about what's happening.

2) You need to understand what the IL code is doing in order to determine which is "better"

3) No. It means it takes fewer instructions to run. However, these individual instructions might use more memory or less. For example, the instruction you were referencing, in one case is creating a Func delegate, and in the other is creating a Converter object. Without more information, it's difficult to tell which of those two things is more expensive.

4) Yes and no....

The problem is that the IL code will tell you what's happening, but it's really the nested calls in IL that are going to be the large performance driver. If the IL code is doing simple operations everywhere, in general the shorter the better (although individual IL operations can vary in speed, themselves). When the code calls into methods or constructors on other types, such as yours, this becomes impossible to tell from this alone. One line of IL can take longer in one case (if it's calling an expensive method, for example) than 50 in another case (where they're doing simple operations).

In your case above, for example, the first 20 operations are very, very fast, wheras the last few take nearly all of your executable time.

这篇关于我可以比较的IL代码,以确定哪些技术是更快,更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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