为什么第二次执行这个组合器比第一次快10倍?

时间:2013-09-06 20:54:44

标签: f#

我正在研究一个解析器组合库,发现了一些我无法解释的行为。我第一次运行组合器时运行速度明显慢于第二次运行组合器。我用这个小应用程序重新启动了行为(运行Release并进行了优化)

let (>>=) first callback state = 
    let reply = first state
    callback reply state

let time f = 
    let start = System.DateTime.Now
    f()
    printfn "%s" ((System.DateTime.Now - start).ToString())

[<EntryPoint>]
let main args = 

    let x1 state = "foo"

    let compound = 
        x1 >>= fun i ->
        x1 >>= fun j ->
        x1 >>= fun a ->
        x1 >>= fun b ->
        x1 >>= fun c ->
        x1 >>= fun d ->
        x1 >>= fun e ->
        x1 >>= fun f ->
        x1 >>= fun j ->                
               fun _ -> [i;j;a;b;c;d;e;f]


    time (fun () -> compound "a" |> ignore)
    time (fun () -> compound "b" |> ignore)
    time (fun () -> compound "c" |> ignore)


    0

运行此输出我得

00:00:00.0090009
00:00:00.0010001
00:00:00

为什么第一次迭代比第二次或第三次迭代慢得多?


编辑,所以我在C#中尝试了这个。它运行得更快,但结果相似。

using System;

namespace fssharp
{
    public delegate string Parser(string state);

    public delegate Parser Callback(string result);

    public class Combinator
    {
        public static Parser Combine(Parser p, Callback callback)
        {
            Parser r = state =>
            {
                var result = p(state);
                return callback(result)(state);
            };

            return r;
        }

        public static string X1(string state)
        {
            return "foo";
        } 
    }
    class Program
    {
        static void Main(string[] args)
        {
            Parser comb = state => 
                                Combinator.Combine(Combinator.X1, result  =>
                                Combinator.Combine(Combinator.X1, result2 =>
                                Combinator.Combine(Combinator.X1, result3 =>
                                Combinator.Combine(Combinator.X1, result4 =>
                                Combinator.Combine(Combinator.X1, result5 =>
                                Combinator.Combine(Combinator.X1, result6 =>
                                Combinator.Combine(Combinator.X1, result7 =>
                                Combinator.Combine(Combinator.X1, result8 =>
                                Combinator.Combine(Combinator.X1, result9 => s => result + result2 + result3 +result4 +result5 +result6 +result7+result8+result9)))
                                ))))))(state);

            var now = DateTime.Now;

            comb("foo");

            Console.WriteLine(DateTime.Now - now);

            now = DateTime.Now;

            comb("foo2");

            Console.WriteLine(DateTime.Now - now);
        }
    }
}

打印出来

00:00:00.0030003
00:00:00

我现在好奇为什么C#在这里更快

1 个答案:

答案 0 :(得分:5)

即使很难,我也无法确定,它是:

  1. JIT:该函数在第一次运行时被JIT',然后它使用已编译的版本

  2. 它检测到使用相同参数调用相同的函数并缓存结果。

  3. 尝试使用其他参数调用它。如果时间保持不变,则为2,如果时间不同则为1