可能重复:
Performance difference between functions and pattern matching in Mathematica
我经常在这里发布的很多答案中发现大量使用纯函数,而且这些解决方案通常比使用命名模式快得多。为什么会这样?为什么纯函数比其他函数更快?是否与mma口译人员的工作量有关?
答案 0 :(得分:8)
首先,让我们考虑一些示例基准:
In[100]:= f[x_]:=x^2;
In[102]:= Do[#^2&[i],{i,300000}]//Timing
Out[102]= {0.406,Null}
In[103]:= Do[f[i],{i,300000}]//Timing
Out[103]= {0.484,Null}
In[104]:= Do[Function[x,x^2][i],{i,300000}]//Timing
Out[104]= {0.578,Null}
由于两个原因,纯函数通常(更快)更快。首先,匿名纯函数(使用插槽定义的函数 - #
和&
)不需要解析变量名称的名称冲突。因此,它们比模式定义的更快,其中发生了一些名称冲突解决。但是你会发现带有命名变量的纯函数实际上比模式定义的更慢,而不是更快。我可以推测这是因为他们还必须解决他们体内可能发生的冲突,而基于规则的冲突则忽略了这些冲突。在任何情况下,速度差异大约为10-20%。
另一个更为戏剧性的区别在于它们用于Map,Scan,Table等功能,因为后者在大型数字(打包)列表上自动编译。但是,虽然通常可以编译纯函数,但模式定义的函数基本上不能,因此它们无法访问这种速度增益。例如:
In[117]:= ff[x_] := Sqrt[x];
In[116]:= Map[Sqrt[#] &, N@Range[100000]]; // Timing
Out[116]= {0.015, Null}
In[114]:= Map[ff, N@Range[100000]]; // Timing
Out[114]= {0.094, Null}
答案 1 :(得分:0)
纯功能有几个优点: - 可以缓存结果。 - 计算可以安全地进行分析。 - 在某些情况下,结果可以在编译时计算(CTFE),并且函数最后不会执行。 - 由于未修改外部作用域,因此无需通过复制传递所有参数。
因此,如果编译器能够相对于这些函数管理优化,那么您的程序将更快。无论是什么语言。
答案 2 :(得分:0)
实际上,模式匹配似乎通常比Function[{u},...]
构造更快,并且与#&
- 类型构造一样快(忽略编译的可能性,这在mma 8中变得更加令人兴奋)。
要看到这个定义一个函数来计算短代码的时间:
SetAttributes[timeshort, HoldAll];
timeshort[expr_] := Module[{t = Timing[expr;][[1]], tries = 1},
While[t < 1.,
tries *= 2;
t = Timing[Do[expr, {tries}];][[1]]];
Return[t/tries]]
然后试试这个:
ClearAll[f]; f[x_] := Cos[x]
Trace[f[5.]]
f[5] // timeshort
ClearAll[f]; f = Function[x, Cos[x]]
Trace[f[5.]]
f[5] // timeshort
ClearAll[f]; f = Cos[#] &
Trace[f[5.]]
f[5] // timeshort
给出
{f[5.],Cos[5.],0.283662}
8.45641\[Times]10^-7
Function[x,Cos[x]]
{{f,Function[x,Cos[x]]},Function[x,Cos[x]][5.],Cos[5.],0.283662}
1.51906\[Times]10^-6
Cos[#1]&
{{f,Cos[#1]&},(Cos[#1]&)[5.],Cos[5.],0.283662}
8.04602\[Times]10^-7
即,模式匹配和#&
比Function
快。我不明白为什么。
编辑:猜猜我应该检查一下belisarius之前提出的问题...请参阅here与我给出的答案基本相同,并阅读评论以进行一些有趣的讨论。
答案 3 :(得分:-1)
是。这意味着它永远不必复制很多东西,因为纯函数不能改变它。列表处理纯粹可以进行一定量的复制,但通常将功能算法安排得高效。一旦编译完东西,命令式代码将快速(几乎总是),但对于解释的Mathematica字节码,纯粹通常很快。