Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern Match in F# much slower than If else / switch in C#? [duplicate]

Possible Duplicate:
F# seems slower than other languages… what can I do to speed it up?

I am a bit curious about the performance of pattern match, so I did the following test:

poolEven contains 10000 elements of 0,1,2,3, (2500 equal)

testSize = 100000

IfelseEven(100000) takes 650ms (switch would be faster but I didn't attach the code) while MatchEven(100000) takes 7000ms that's 10x time

Does the performance degradation come from Array.Fold? I am 100% sure that if I go for IEnumerable.Aggregate the speed would greatly decrease. But I thought F# handled Array.Fold better than C# with IEnumerable.Aggregate. I want to compare performance of most common (equivalent) ways of coding in 2 languages but not rigid ways to make them identical.

The tests are done in x64 release, with 10+ trials taken average with proper warm up

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);
}

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
like image 796
colinfang Avatar asked Aug 29 '12 16:08

colinfang


People also ask

What is pattern matching in F#?

Pattern matching is ubiquitous in F#. It is used for binding values to expressions with let , and in function parameters, and for branching using the match..with syntax.

What is pattern matching in code?

Pattern matching provides a way to conditionally execute code when the shape of some data matches a particular pattern. It is similar to switch-case statements in other languages, but it can be more expressive and includes some extra safeguards. Pattern matching is often used with variants.

What is pattern matching give an example?

For example, x* matches any number of x characters, [0-9]* matches any number of digits, and . * matches any number of anything. A regular expression pattern match succeeds if the pattern matches anywhere in the value being tested.

Is there pattern matching in JavaScript?

JavaScript uses the RegExp (short for Regular Expression) object to handle pattern matching. This object holds the pattern definition, as well as provides methods for performing matching. You'll begin by learning how to define patterns and then by learning how to use the RegExp objects to test for pattern matches.


2 Answers

Voting to close—we could play this game all day long. For more commentary on why different code might have different execution times see this question and answers. If you just want to speed up your F# function, try this:

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

By my measurements this handily licks the C# function (and it's still shorter and more readable):

C# 5655
F# 4003

Incidentally, leppie nailed it in the comments. I profiled your code and 78% of the time was spent in Array.fold—not good in a tight loop.

like image 150
Daniel Avatar answered Oct 19 '22 02:10

Daniel


As mentioned in the comments, by using an entirely different pattern, you are not really getting a comparison of match vs if/elseif in isolation. Comparison of loops vs fold vs recurse is an entirely different question.

Using a more direct comparison (loops, same as Daniel's response), I got below results. Release build, .NET 4.5, x64 target arch.

  • C# and F# if\elseif approaches run pretty much exactly the same (in this contrived example).

  • F# match was consistently faster than if\elseif in either language (in this contrived example)

  • C# switch was consistently fastest (in this contrived example).

like image 42
latkin Avatar answered Oct 19 '22 04:10

latkin