Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#是否在循环/lambda语句中自动优化代码?_C# - Fatal编程技术网

C#是否在循环/lambda语句中自动优化代码?

C#是否在循环/lambda语句中自动优化代码?,c#,C#,例如,在Javascript中,强烈建议将函数调用置于循环之外,以获得更好的性能: var id = someIdType.ToString(); someList.Where(a => a.id == id) ... 那么C#呢?还是编译器/运行时采用内部优化/缓存 someList.Where(a => a.id == someIdType.ToString()) ... 可能是一个noob问题,以前曾被问过,但找不到参考。将为列表中的每个元素执行lambda。。因此,代码s

例如,在Javascript中,强烈建议将函数调用置于循环之外,以获得更好的性能:

var id = someIdType.ToString();
someList.Where(a => a.id == id) ...
那么C#呢?还是编译器/运行时采用内部优化/缓存

someList.Where(a => a.id == someIdType.ToString()) ...

可能是一个noob问题,以前曾被问过,但找不到参考。

将为列表中的每个元素执行lambda。。因此,代码
someIdType.ToString()
将对每个元素执行。我认为编译器或运行时不会为您缓存它。(将在闭包中捕获AFAIK
someIdType
,但不会捕获
.ToString()

编辑: 最初的问题只是关于“做什么?”,而不是关于“为什么?”,但仍然有一些评论和其他答案试图回答/证明“为什么?”

鉴于人们对“为什么?”如此感兴趣,我正在编辑我的答案,陈述我对“为什么”的看法。 i、 e.如果您看一下,对于任何相关场景,规范都谈到了捕获变量
捕获表达式
。 这就是编译器的行为方式的原因。。因为其不在规范中。为什么不在规范中,这是C#设计团队可以回答的问题。。其余部分是推测,如果考虑捕获表达式的
功能,部分或全部可能有价值,也可能没有价值。

C#code:

List List=新列表();
其中(a=>a==typeof(String.ToString());
MSIL中的Lambda表达式,调试配置:

.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init ([0] bool CS$1$0000)
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  stloc.0
  IL_0016:  br.s       IL_0018
  IL_0018:  ldloc.0
  IL_0019:  ret
} // end of method Program::'<Main>b__0'
.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type     [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  ret
} // end of method Program::'<Main>b__0'
.method private hidebysing static bool'b__0'(字符串a)cil托管
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()=(01 00)
//代码大小26(0x1a)
.maxstack 2
.locals init([0]bool CS$1$0000)
IL_0000:ldarg.0
IL_0001:ldtoken[mscorlib]System.String
IL_0006:调用类[mscorlib]System.Type[mscorlib]System.Type::GetTypeFromHandle(valuetype[mscorlib]System.RuntimeTypeHandle)
IL_000b:callvirt实例字符串[mscorlib]System.Object::ToString()
IL_0010:调用bool[mscorlib]System.String::op_Equality(String,
(字符串)
IL_0015:stloc.0
IL_0016:br.s IL_0018
IL_0018:ldloc.0
IL_0019:ret
}//方法结束程序::'b__0'
MSIL中的Lambda表达式,发布配置:

.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init ([0] bool CS$1$0000)
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  stloc.0
  IL_0016:  br.s       IL_0018
  IL_0018:  ldloc.0
  IL_0019:  ret
} // end of method Program::'<Main>b__0'
.method private hidebysig static bool  '<Main>b__0'(string a) cil managed
{
  .custom instance void     [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldtoken    [mscorlib]System.String
  IL_0006:  call       class [mscorlib]System.Type     [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_0010:  call       bool [mscorlib]System.String::op_Equality(string,
                                                             string)
  IL_0015:  ret
} // end of method Program::'<Main>b__0'
.method private hidebysing static bool'b__0'(字符串a)cil托管
{
.custom instance void[mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()=(01 00)
//代码大小22(0x16)
.maxstack 8
IL_0000:ldarg.0
IL_0001:ldtoken[mscorlib]System.String
IL_0006:调用类[mscorlib]System.Type[mscorlib]System.Type::GetTypeFromHandle(valuetype[mscorlib]System.RuntimeTypeHandle)
IL_000b:callvirt实例字符串[mscorlib]System.Object::ToString()
IL_0010:调用bool[mscorlib]System.String::op_Equality(String,
(字符串)
IL_0015:ret
}//方法结束程序::'b__0'

两个版本都调用
typeof(String).ToString())
,每次迭代都会调用这个lambda。没有IL级别的优化,JIT编译不会在这里添加任何内容。原因是:该功能可能有副作用。

您尝试过什么?您是否有一个可以对其进行测量的示例应用程序?这是一个非常简单的测试,使用您提供的示例(查找字符串)在1000000个元素的列表中进行测试,后者的速度慢4倍,约118ms,而不是约32ms。至少在我的工作站上;)在您进行任何手动优化之前,重要的是要知道这样做是否值得——这段代码实际上是应用程序性能的瓶颈吗?如果不是,就选择你认为读起来最好的表格,别管它。如果是瓶颈,那么尝试不同的变体并选择性能最好的变体。不要试图学习成千上万的“性能”规则,然后严格按照它们编写代码。最好编写清晰的代码,让您能够在6个月内返回并快速理解,而不是试图编写所有代码,就好像每个ms都计数一样。编译器不能也不会缓存它,因为在C#中,函数不是纯函数,也就是说,它们可能会产生副作用或在同一个参数上返回不同的值(查看
Random.Next()
)这是合理的。另一个问题。如果调用的方法具有
Pure
属性怎么办?这有意义吗?@serdar AFAIK不,它没有启用此类优化。@Madsorcher事实上,如果它启用了这种优化,那么在我们错误地将纯属性添加到具有副作用的方法中时会导致非常大的问题。即使可以可靠地确定哪些函数是“纯”函数,您仍然会遇到另一个问题:纯函数可能仍然会抛出异常,如果该纯函数在循环中被调用,而该循环根本不应该执行(假设您在空列表上使用
foreach
),那么您应该不会得到异常。如果调用只是从循环中移出,你会得到一个异常。我不认为这是因为函数可能有副作用。。。例如,在lambda中访问的成员可能是字段,而不是函数。。。即使字段访问没有副作用,它也不会被缓存。。所以说“原因是:功能可能有副作用”并不准确。。所以我只能说。。编译器/运行时不缓存它。。为什么?谁知道呢?也许他们从来没有考虑过。。可能有10个原因,包括副作用。。也许他们发现这个特性总体上是低投资回报率的。@VikasGupta-也许最好将其表述为“原因之一”。我测试了这个