可能重复:
F# seems slower than other languages… what can I do to speed it up?
我对模式匹配的表现有点好奇,所以我做了以下测试:
poolEven
包含10000个元素0,1,2,3,(2500等于)
testSize = 100000
IfelseEven(100000)
需要650毫秒(切换会更快,但我没有附加代码),而MatchEven(100000)
需要7000毫秒,这是10倍的时间
性能下降是否来自Array.Fold
?我100%肯定,如果我选择IEnumerable.Aggregate
,速度会大大降低。 但我认为F#处理Array.Fold
比使用IEnumerable.Aggregate
的C#更好。我想比较两种语言中最常见(等效)编码方式的性能,而不是使它们完全相同的严格方法。
测试在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);
}
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
答案 0 :(得分:11)
投票结束 - 我们可以整天玩这个游戏。有关为什么不同代码可能具有不同执行时间的更多注释,请参阅this question and answers。如果您只想加快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
通过我的测量,这方便地舔C#功能(它仍然更短,更可读):
C#5655顺便说一句,leppie在评论中钉了它。我描述了你的代码,78%的时间花在了Array.fold
上 - 在一个紧密的循环中并不好。
答案 1 :(得分:7)
正如评论中所提到的,通过使用完全不同的模式,您实际上并未真正对match
与if/elseif
进行单独比较。循环与折叠与递归的比较是一个完全不同的问题。
使用更直接的比较(循环,与Daniel的回答相同),我得到了以下结果。发布版本,.NET 4.5,x64目标arch。
C#和F#if\elseif
方法几乎完全相同(在这个人为的例子中)。
F#match
的速度始终高于if\elseif
语言(在这个人为的例子中)
C#switch
一直是最快的(在这个人为的例子中)。