gpt4 book ai didi

c# - IL 优化尝试导致执行速度变慢

转载 作者:行者123 更新时间:2023-11-30 14:57:17 28 4
gpt4 key购买 nike

更多地考虑这是一个学术问题而不是实际问题。

在重新发明轮子时,即编写一个迷你 ORM/类型映射器时,我发出了一些 IL 以将对象的属性转换为添加到 SqlCommand 的 SqlParameters。

我的第一次尝试基本上是编写 C# 代码并将其转换为 IL 1:1,从而生成以下代码(完美运行)。请注意,注释表示运行以下发出的 IL 后的堆栈:

int paramLocIndex = localIndex++;

// Get the type handler [typeHandler]
il.Emit(OpCodes.Call, ClrTypeHandlers[prop.PropertyType].GetType().GetMethod("GetTypeHandler", BindingFlags.NonPublic | BindingFlags.Static));

// Load the object [typeHandler, object]
il.Emit(OpCodes.Ldloc_0);

// Get the property value [typeHandler, value]
il.Emit(OpCodes.Call, prop.GetMethod);

// Box the value [typeHandler, boxedValue]
il.Emit(OpCodes.Box, prop.PropertyType);

// Let the type handler create the param [param]
il.Emit(OpCodes.Callvirt, typeof(SqlTypeHandler).GetMethod("CreateParamFromValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object) }, null));

// Store the parameter as a variable []
il.DeclareLocal(typeof(SqlParameter));
il.Emit(OpCodes.Stloc, paramLocIndex);

// Load the parameter again [param]
il.Emit(OpCodes.Ldloc, paramLocIndex);

// Load the parameter name [param, paramName]
il.Emit(OpCodes.Ldstr, paramName);

// Set the parameter name []
il.Emit(OpCodes.Call, typeof(SqlParameter).GetMethod("set_ParameterName"));

// Load the command [cmd]
il.Emit(OpCodes.Ldarg_0);

// Load the parameter collection [paramCollection]
il.Emit(OpCodes.Call, typeof(SqlCommand).GetMethod("get_Parameters"));

// Load the parameter [paramCollection, param]
il.Emit(OpCodes.Ldloc, paramLocIndex);

// Add the parameter to the collection [param]
il.Emit(OpCodes.Call, typeof(SqlParameterCollection).GetMethod("Add", new[] { typeof(SqlParameter) }));

// Get rid of the added parameter, as returned by SqlParameterCollection.Add []
il.Emit(OpCodes.Pop);

虽然上述方法有效,但我想尝试对其进行优化。这导致了以下代码,它也可以完美运行:

// Load the command [cmd]
il.Emit(OpCodes.Ldarg_0);

// Load the parameter collection [paramCollection]
il.Emit(OpCodes.Call, typeof(SqlCommand).GetMethod("get_Parameters"));

// Get the type handler [paramCollection, typeHandler]
il.Emit(OpCodes.Call, ClrTypeHandlers[prop.PropertyType].GetType().GetMethod("GetTypeHandler", BindingFlags.NonPublic | BindingFlags.Static));

// Load the object [paramCollection, typeHandler, object]
il.Emit(OpCodes.Ldloc_0);

// Get the property value [paramCollection, typeHandler, value]
il.Emit(OpCodes.Call, prop.GetMethod);

// Box the value [paramCollection, typeHandler, boxedValue]
il.Emit(OpCodes.Box, prop.PropertyType);

// Let the type handler create the param [paramCollection, param]
il.Emit(OpCodes.Callvirt, typeof(SqlTypeHandler).GetMethod("CreateParamFromValue", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(object) }, null));

// Add the parameter to the collection [param]
il.Emit(OpCodes.Call, typeof(SqlParameterCollection).GetMethod("Add", new[] { typeof(SqlParameter) }));

// Load the parameter name [param, paramName]
il.Emit(OpCodes.Ldstr, paramName);

// Set the parameter name []
il.Emit(OpCodes.Call, typeof(SqlParameter).GetMethod("set_ParameterName"));

虽然优化尝试导致更少的指令、避免变量等,但它仍然运行得更慢。第一次尝试在 21500 个滴答中运行,而“优化”版本在 75000 个滴答中运行。

这两个都非常快,但我很好奇为什么第一个运行得快得多。我知道从 IL 到机器代码还有第二级编译——答案可能在于 IL 编译器执行的优化。问题是,如果我想进一步探索这个问题,我有什么选择?第二次 IL 尝试运行较慢的明显原因是什么?

最佳答案

我认为它与 IL 编译优化没有任何关系,但与框架处理添加到 SqlParameterCollection 的更无聊的方式有关。

在第一个(较长的)方法中,您:

  • 创建 SqlParameter
  • 分配其属性名称
  • 将其加入收藏

在优化版本中你:

  • 创建 SqlParameter
  • 将其加入收藏
  • 分配其属性名称

注意到区别了吗?最后 2 个步骤被调换了,这看起来相当学术,但如果你启动反射器并查看 SqlParameterCollection 源代码,你会偶然发现这段代码:

private void Validate(int index, object value)
{
/* snip */
if (((SqlParameter) value).ParameterName.Length == 0)
{
string str;
index = 1;
do
{
str = "Parameter" + index.ToString(CultureInfo.CurrentCulture);
index++;
}
while (-1 != this.IndexOf(str));
((SqlParameter) value).ParameterName = str;
}
}

当您将它添加到没有参数名称的集合中时,会为其生成一个参数名称,并且此过程涉及分配、循环和查找列表,这应该很容易解释您注意到的额外运行时间。

如果您试图避免创建局部变量 SqlTypeHandler 似乎是您控制的类?因此,您可以将参数名称作为参数添加到 CreateParamFromValue 方法并在其中分配它,这样当它添加到集合中时它已经有一个名称。

关于c# - IL 优化尝试导致执行速度变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21032177/

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