我一直在研究我的ECMAScript运行时的JSON代码,我决定运行一个实验。以下str
函数有4个逻辑步骤,我将其分解为函数并将其标记为内联。
and private str (state:StringifyState) (key:string) (holder:IObject) : IDynamic =
let inline fourth (value:IDynamic) =
match value.TypeCode with
| LanguageTypeCode.Null ->
state.environment.CreateString "null" :> IDynamic
| LanguageTypeCode.Boolean ->
let v = value :?> IBoolean
state.environment.CreateString (if v.BaseValue then "true" else "false") :> IDynamic
| LanguageTypeCode.String ->
let v = value :?> IString
state.environment.CreateString (quote v.BaseValue) :> IDynamic
| LanguageTypeCode.Number ->
let v = value :?> INumber
if not (Double.IsInfinity(v.BaseValue))
then v.ConvertToString() :> IDynamic
else state.environment.CreateString "null" :> IDynamic
| LanguageTypeCode.Object ->
let v = value :?> IObject
let v = if v.Class = "Array" then ja state v else jo state v
state.environment.CreateString v :> IDynamic
| _ ->
state.environment.Undefined :> IDynamic
let inline third (value:IDynamic) =
match value.TypeCode with
| LanguageTypeCode.Object ->
let v = value :?> IObject
match v.Class with
| "Number" ->
fourth (v.ConvertToNumber())
| "String" ->
fourth (v.ConvertToString())
| "Boolean" ->
fourth (v.ConvertToBoolean())
| _ ->
fourth value
| _ ->
fourth value
let inline second (value:IDynamic) =
match state.replacerFunction with
| :? ICallable as f ->
let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic; value |])
let value = f.Call (state.environment, holder :> IDynamic, args)
third value
| _ ->
third value
let inline first (value:IDynamic) =
match value with
| :? IObject as v ->
let toJSON = v.Get "toJSON"
match toJSON with
| :? ICallable as f ->
let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic |])
let value = f.Call (state.environment, value, args)
second value
| _ ->
second value
| _ ->
second value
first (holder.Get key)
我使用完全优化进行编译,并使用Reflector打开生成的程序集以查看结果。
[CompilationArgumentCounts(new int[] { 1, 1, 1 })]
internal static IDynamic str(StringifyState state, string key, IObject holder)
{
IObject obj3;
ICallable callable;
ICallable callable2;
IArgs args;
IDynamic dynamic3;
IDynamic dynamic4;
ICallable callable3;
IDynamic dynamic5;
IBoolean flag;
IString str;
INumber number;
IObject obj4;
string str2;
INumber number2;
IObject obj5;
string str3;
IString str4;
IBoolean flag2;
IDynamic thisBinding = holder.Get(key);
IObject obj2 = thisBinding as IObject;
if (obj2 == null)
{
callable = state.replacerFunction@ as ICallable;
if (callable == null)
{
switch (thisBinding.TypeCode)
{
case LanguageTypeCode.Object:
obj3 = (IObject) thisBinding;
str2 = obj3.Class;
if (!string.Equals(str2, "Number"))
{
if (string.Equals(str2, "String"))
{
dynamic3 = obj3.ConvertToString();
switch (dynamic3.TypeCode)
{
case LanguageTypeCode.Null:
return (IDynamic) state.environment@.CreateString("null");
case LanguageTypeCode.Boolean:
flag = (IBoolean) dynamic3;
return (IDynamic) state.environment@.CreateString(!flag.BaseValue ? "false" : "true");
case LanguageTypeCode.String:
str4 = (IString) dynamic3;
return (IDynamic) state.environment@.CreateString(quote(str4.BaseValue));
case LanguageTypeCode.Number:
number = (INumber) dynamic3;
if (double.IsInfinity(number.BaseValue))
{
return (IDynamic) state.environment@.CreateString("null");
}
return (IDynamic) number.ConvertToString();
// ... I removed a large amount of code.
return (IDynamic) state.environment@.Undefined;
}
显然,inline
修饰符非常直观。代码非常庞大,一些初步测试非常有效。如果他们不关心生成的程序集的大小,可以考虑将所有函数内联。我可以遵循哪些指导原则来了解何时使用inline
是合适的?如果可能的话,我希望避免每次都要测量性能来确定这一点。
答案 0 :(得分:4)
如果您仅仅出于性能考虑而使用inline
,那么我认为所有典型的与性能相关的建议都适用。最重要的是,设置性能目标并为热点配置应用程序。然后使用inline
如果您有理由相信它会提高性能,并进行测试以验证它是否有效。请记住,F#编译器生成的IL无论如何都是JIT编译的,因此即使您不在F#中使用inline
,也可以在编译到机器代码中内联小函数(就IL大小而言)。代码。
当我想使用静态解析的类型变量时(例如,由于成员约束),我通常只使用inline
。
答案 1 :(得分:2)
我同意kvb的回答,但这里有两个具体的理由不
如果他们不关心所得到的程序集的大小,请考虑对其所有函数进行内联。
显而易见的情况是内联匿名函数不起作用。
更多内联(特别是大功能) - >较少(有效)的代码适合缓存 - >程序工作得比较慢。