F#中的模式匹配比C#中的If else/switch慢得多?

col*_*ang 6 c# performance f# pattern-matching

可能重复:
F#似乎比其他语言慢...我该怎么做才能加快速度?

我对模式匹配的性能有点好奇,所以我做了以下测试:

poolEven 包含10000个元素0,1,2,3,(2500相等)

testSize = 100000

IfelseEven(100000) 花费650毫秒(开关会更快,但我没有附加代码),而MatchEven(100000)需要7000毫秒,这是10倍的时间

性能下降是否来自Array.Fold?我100%肯定,如果我IEnumerable.Aggregate的速度会大大降低.但我认为F#处理Array.Fold比C#更好IEnumerable.Aggregate.我想比较两种语言中最常见(等效)编码方式的性能,而不是使它们相同的严格方法.

测试在x64版本中完成,平均10次试验进行适当的预热

C#:

public void IfelseEven(int testSize)
{
    Ifelse(testSize, poolEven);
}

void Ifelse(int testSize, int[] pool)
{
    long sum = 0;
    for (int i = 0; i < testSize; i++)
    {
        for (int j = 0; j < poolCapacity;j++ )
        {
            var item = pool[j];
            if (item == 0)
            {
                sum += 5;
            }
            else if (item == 1)
            {
                sum += 1;
            }
            else if (item == 2)
            {
                sum += 2;
            }
            else if (item == 3)
            {
                sum += 3;
            }
            else
            {
                sum += 4;
            }
        }
    }
}

public void MatchEven(int testSize)
{
    PatternMatch.myMatch(testSize, poolEven);
}
Run Code Online (Sandbox Code Playgroud)

F#:

module PatternMatch

let mat acc elem =
    acc +
    match elem with
    | 0 -> 5L
    | 1 -> 1L
    | 2 -> 2L
    | 3 -> 3L
    | _ -> 4L

let sum (pool:int[])=
    Array.fold mat 0L pool;

let myMatch testSize pool=
    let mutable tmp = 0L
    for i=0 to testSize do
        tmp <- sum(pool) + tmp
    tmp
Run Code Online (Sandbox Code Playgroud)

Dan*_*iel 11

投票结束 - 我们可以整天玩这个游戏.有关为什么不同的代码可能具有不同的执行时间的更多评论,请参阅此问题和答案.如果您只想加快F#功能,请尝试以下方法:

let ifElse testSize (pool: _[]) = 
  let mutable sum = 0L
  for i = 0 to testSize - 1 do
    for j = 0 to pool.Length - 1 do
      match pool.[j] with
      | 0 -> sum <- sum + 5L
      | 1 -> sum <- sum + 1L
      | 2 -> sum <- sum + 2L
      | 3 -> sum <- sum + 3L
      | _ -> sum <- sum + 4L
  sum
Run Code Online (Sandbox Code Playgroud)

通过我的测量,这方便地舔C#功能(它仍然更短,更可读):

C#5655
F#4003

顺便说一句,leppie在评论中钉了它.我描述了你的代码,78%的时间花在了Array.fold- 在一个紧凑的循环中不好.


lat*_*kin 7

正如评论中所提到的,通过使用完全不同的模式,您实际上并没有真正得到matchvs if/elseif的隔离比较.循环与折叠与递归的比较是一个完全不同的问题.

使用更直接的比较(循环,与Daniel的响应相同),我得到了以下结果.发布版本,.NET 4.5,x64目标arch.

  • C#和F#if\elseif方法几乎完全相同(在这个人为的例子中).

  • F#match一直比if\elseif任何一种语言都快(在这个人为的例子中)

  • C#switch一直是最快的(在这个人为的例子中).