我正在研究一个解析器组合库,发现了一些我无法解释的行为。我第一次运行组合器时运行速度明显慢于第二次运行组合器。我用这个小应用程序重新启动了行为(运行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#在这里更快
答案 0 :(得分:5)
即使很难,我也无法确定,它是:
JIT:该函数在第一次运行时被JIT',然后它使用已编译的版本
它检测到使用相同参数调用相同的函数并缓存结果。
尝试使用其他参数调用它。如果时间保持不变,则为2,如果时间不同则为1