dev*_*ium 5 .net c# performance f#
我想知道为什么我在C#和F#中显然相同的算法之间得到如此不同的结果.
F#代码变体:
open System
{ 1I..(bigint (Int32.MaxValue / 100)) } |> Seq.sum
let mutable sum = 0I
for i in 1I..(bigint (Int32.MaxValue / 100)) do
sum <- sum + i
sum
let sum = ref 0I
for i in 1I..(bigint (Int32.MaxValue / 100)) do
sum := !sum + i
sum
Run Code Online (Sandbox Code Playgroud)
完整的F#代码(4s):
[<EntryPoint>]
let main argv =
let sw = new Stopwatch()
sw.Start()
printfn "%A" ({ 1I..(bigint (Int32.MaxValue / 100)) } |> Seq.sum)
sw.Stop()
printfn "took %A" sw.Elapsed
Console.ReadKey() |> ignore
0
Run Code Online (Sandbox Code Playgroud)
完整的C#代码(22s):
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
BigInteger sum = new BigInteger(0);
BigInteger max = new BigInteger(Int32.MaxValue / 100);
Console.WriteLine(max);
for (BigInteger i = new BigInteger(1); i <= max; ++i)
{
sum += i;
}
sw.Stop();
Console.WriteLine(sum);
Console.WriteLine(sw.Elapsed);
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
F#代码在其任何变体上都需要超过22秒(我假设不同的实现会产生不同的运行时间,但似乎并非如此).另一方面,C#代码似乎更快.两者都产生相同的最终总和结果,所以我猜算法是等价的.我仔细检查了,F#代码似乎是用--optimize+标志编译的.
难道我做错了什么?
转换F#代码
{ 1I..(bigint (Int32.MaxValue / 100)) } |> Seq.sum;;
Real: 00:00:14.014, CPU: 00:00:14.196, GC gen0: 1743, gen1: 0
Run Code Online (Sandbox Code Playgroud)
至
let mutable t = 1I
let mutable res = 0I
let max = bigint (Int32.MaxValue / 100)
while t < max do
res <- res + t
t <- t + 1I;;
Real: 00:00:05.379, CPU: 00:00:05.450, GC gen0: 748, gen1: 0
Run Code Online (Sandbox Code Playgroud)
接近三倍的速度,也更接近原始的C#代码.
最可能的原因是,无论{...}和for i in ...创建一个虚拟的seq.通过删除它,您可以避免seq开销.
编辑
出于某种原因,F#为此代码生成了大量的IL,并使用了一个非常奇怪的比较.
如果我们明确强制比较,速度加倍(这有点荒谬)
对于我来说,这段代码与C#完全相同(单声道).
let mutable t = 1I
let mutable res = 0I
let max = (bigint (Int32.MaxValue / 100));;
while System.Numerics.BigInteger.op_GreaterThan(max,t) do
res <- res + t;t<-System.Numerics.BigInteger.op_Increment(t)
printfn "%A" res
Run Code Online (Sandbox Code Playgroud)
但是不必要地冗长.
我可能会提交一个编译错误.
| 归档时间: |
|
| 查看次数: |
769 次 |
| 最近记录: |