我很惊讶 List 范围在下面的例子中慢了多少。在我的机器上,for 循环快了 8 倍左右。
是否首先创建了 10,000,000 个元素的实际列表?如果是这样,是否有原因(除了尚未完成)为什么编译器无法对其进行优化?
open System
open System.Diagnostics
let timeFunction f v =
let sw = Stopwatch.StartNew()
let result = f v
sw.ElapsedMilliseconds
let length = 10000000
let doSomething n =
(float n) ** 0.1 |> ignore
let listIter n =
[1..length] |> List.iter (fun x -> doSomething (x+n))
let forLoop n =
for x = 1 to length do
doSomething (x+n)
printf "listIter : %d\n" (timeFunction listIter 1) // c50
GC.Collect()
printf "forLoop : %d\n" (timeFunction forLoop 1) // c1000
GC.Collect()
最佳答案
使用 ILSpy,listIter
看起来像这样:
public static void listIter(int n)
{
ListModule.Iterate<int>(
new listIter@17(n),
SeqModule.ToList<int>(
Operators.CreateSequence<int>(
Operators.OperatorIntrinsics.RangeInt32(1, 1, 10000000)
)
)
);
}
以下是涉及的基本步骤:
RangeInt32
创建一个 IEnumerable
(莫名其妙地被 CreateSequence
包裹了)SeqModule.ToList
从该序列构建一个列表 listIter@17
的一个实例(你的 lambda)是新的 ListModule.Iterate
遍历列表,为每个元素调用 lambda 对比
forLoop
,这看起来与您所写的没有太大区别:public static void forLoop(int n)
{
for (int x = 1; x < 10000001; x++)
{
int num = x + n;
double num2 = Math.Pow((double)num, 0.1);
}
}
...否
IEnumerable
、lambda(自动内联)或列表创建。正在完成的工作量可能存在显着差异。编辑
出于好奇,这里是
list
的 FSI 时间安排, seq
, 和 for
循环版本:listIter - Real: 00:00:03.889, CPU: 00:00:04.680, GC gen0: 57, gen1: 51, gen2: 6 seqIter - Real: 00:00:01.340, CPU: 00:00:01.341, GC gen0: 0, gen1: 0, gen2: 0 forLoop - Real: 00:00:00.565, CPU: 00:00:00.561, GC gen0: 0, gen1: 0, gen2: 0
and the seq
version for reference:
let seqIter n =
{1..length} |> Seq.iter (fun x -> doSomething (x+n))
关于list - 为什么 F# 列表范围比 for 循环慢这么多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12841704/