我编写了一个简单的测试,该测试创建一个变量,将其初始化为零,并递增100000000次。
C ++在0.36 s内完成了它。最初的C#版本仅需0.33s,而12秒内仅需0.8s F#。
我不使用任何功能,因此默认情况下通用没有问题
F#代码
open System
open System.Diagnostics
// Learn more about F# at http://fsharp.org
// See the 'F# Tutorial' project for more help.
[<EntryPoint>]
let main argv =
let N = 100000000
let mutable x = 0
let watch = new Stopwatch();
watch.Start();
for i in seq{1..N} do
x <- (x+1)
printfn "%A" x
printfn "%A" watch.Elapsed
Console.ReadLine()
|> ignore
0 // return an integer exit code
C ++代码
#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
const int N = 100000000;
int x = 0;
double start = clock();
for(int i=0;i<N;++i)
{
x = x + 1;
}
printf("%d\n",x);
printf("%.4lf\n",(clock() - start)/CLOCKS_PER_SEC);
return 0;
}
C#代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace SpeedTestCSharp
{
class Program
{
static void Main(string[] args)
{
const int N = 100000000;
int x = 0;
Stopwatch watch = new Stopwatch();
watch.Start();
foreach(int i in Enumerable.Range(0,N))
//Originally it was for(int i=0;i<N;++i)
{
x = x + 1;
}
Console.WriteLine(x);
Console.WriteLine(watch.Elapsed);
Console.ReadLine();
}
}
}
编辑
替换for (int i = 0; i < N; ++i)
为foreach(int i in Enumerable.Range(0,N))
C#程序可以在0.8s左右的时间内运行,但仍比f#快得多
编辑
更换DateTime
用StopWatch
的为F#/ C#。结果是一样的
这肯定是由于使用表达式而直接发生的:
for i in seq{1..N} do
在我的机器上,结果如下:
1亿
00:00:09.1500924
如果我将循环更改为:
for i in 1..N do
结果发生了巨大变化:
1亿
00:00:00.1001864
为什么?
这两种方法生成的IL完全不同。第二种情况,使用1..N
语法的方式与C#for(int i=1; i<N+1; ++i)
循环相同。
第一种情况非常不同,此版本产生完整序列,然后由foreach循环枚举。
所使用的C#和F#版本IEnumerables
不同,因为它们使用不同的范围函数来生成它们。
C#版本用于System.Linq.Enumerable.RangeIterator
生成值范围,而F#版本使用Microsoft.FSharp.Core.Operators.OperatorIntrinsics.RangeInt32
。我认为可以肯定地说,在这种特殊情况下,我们在C#和F#版本之间看到的性能差异是这两个函数的性能特征造成的。
svick在其注释中指出+
操作符实际上是作为参数传递给integralRangeStep
函数的,这是正确的。
对于非平凡的情况,n <> m
这会导致使用ProperIntegralRangeEnumerator
以下实现的F#编译器:https : //github.com/Microsoft/visualfsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs #L6463
let inline integralRangeStepEnumerator (zero,add,n,step,m,f) : IEnumerator<_> =
// Generates sequence z_i where z_i = f (n + i.step) while n + i.step is in region (n,m)
if n = m then
new SingletonEnumerator<_> (f n) |> enumerator
else
let up = (n < m)
let canStart = not (if up then step < zero else step > zero) // check for interval increasing, step decreasing
// generate proper increasing sequence
{ new ProperIntegralRangeEnumerator<_,_>(n,m) with
member x.CanStart = canStart
member x.Before a b = if up then (a < b) else (a > b)
member x.Equal a b = (a = b)
member x.Step a = add a step
member x.Result a = f a } |> enumerator
我们可以看到单步执行Enumerator会导致对提供的add
函数的调用,而不是更直接直接的加法。
注意:所有计时都在“释放”模式下运行(尾部呼叫:打开,优化:打开)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句