我是否滥用内联修饰符?

时间:2010-12-28 03:10:47

标签: f# inline

我一直在研究我的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是合适的?如果可能的话,我希望避免每次都要测量性能来确定这一点。

2 个答案:

答案 0 :(得分:4)

如果您仅仅出于性能考虑而使用inline,那么我认为所有典型的与性能相关的建议都适用。最重要的是,设置性能目标并为热点配置应用程序。然后使用inline如果您有理由相信它会提高性能,并进行测试以验证它是否有效。请记住,F#编译器生成的IL无论如何都是JIT编译的,因此即使您不在F#中使用inline,也可以在编译到机器代码中内联小函数(就IL大小而言)。代码。

当我想使用静态解析的类型变量时(例如,由于成员约束),我通常只使用inline

答案 1 :(得分:2)

我同意kvb的回答,但这里有两个具体的理由不

  

如果他们不关心所得到的程序集的大小,请考虑对其所有函数进行内联。

  1. 显而易见的情况是内联匿名函数不起作用。

  2. 更多内联(特别是大功能) - >较少(有效)的代码适合缓存 - >程序工作得比较慢。