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
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.
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.
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.
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.
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With