在 Mathematica 中总是有几种方法可以做同样的事情。例如,在为我最近的问题调整 WReach 的解决方案时,我 used Condition
:
ClearAll[ff];
SetAttributes[ff, HoldAllComplete];
ff[expr_] /; (Unset[done]; True) :=
Internal`WithLocalSettings[Null, done = f[expr],
AbortProtect[If[! ValueQ[done], Print["Interrupt!"]]; Unset[done]]]
然而,我们可以用
Block
做同样的事情。 :ClearAll[ff];
SetAttributes[ff, HoldAllComplete];
ff[expr_] :=
Block[{done},
Internal`WithLocalSettings[Null, done = f[expr],
AbortProtect[If[! ValueQ[done], Print["Interrupt!"]]]]]
或与
Module
:ClearAll[ff];
SetAttributes[ff, HoldAllComplete];
ff[expr_] :=
Module[{done},
Internal`WithLocalSettings[Null, done = f[expr],
AbortProtect[If[! ValueQ[done], Print["Interrupt!"]]]]]
可能还有其他几种方法可以做到这一点。从内存和 CPU 使用的角度来看,哪种方式最有效(
f
可能会返回非常大的数据数组 - 但可能会返回非常小的数据)?
最佳答案
Module
和 Block
都非常有效,因此它们引起的开销只有在您本地化其变量的函数的主体执行的很少时才会注意到。开销有两个主要原因:作用域构造开销(作用域构造必须分析它们所包含的代码以解决可能的名称冲突和绑定(bind)变量 - 这发生在 Module
和 Block
中),以及创建和销毁新符号的开销在符号表中(仅适用于 Module
)。出于这个原因,Block
稍微快一些。要查看速度有多快,您可以做一个简单的实验:
In[14]:=
Clear[f,fm,fb,fmp];
f[x_]:=x;
fm[x_]:=Module[{xl = x},xl];
fb[x_]:=Block[{xl = x},xl];
Module[{xl},fmp[x_]:= xl=x]
我们在这里定义了 4 个函数,具有最简单的主体 - 只需返回参数,可能分配给局部变量。我们可以预期效果在这里最为明显,因为 body 的作用很小。
In[19]:= f/@Range[100000];//Timing
Out[19]= {0.063,Null}
In[20]:= fm/@Range[100000];//Timing
Out[20]= {0.343,Null}
In[21]:= fb/@Range[100000];//Timing
Out[21]= {0.172,Null}
In[22]:= fmp/@Range[100000];//Timing
Out[22]= {0.109,Null}
从这些时序中,我们看到
Block
比 Module
快大约两倍,但是在最后一个函数中仅使用一次由 Module
创建的持久变量的版本比 Block
效率高出大约两倍,并且几乎与简单的函数调用一样快(因为持久变量只创建一次,并且在应用函数时没有作用域开销)。对于实际功能,大多数时候,
Module
或 Block
的开销应该无关紧要,所以我会使用更安全的东西(通常是 Module
)。如果确实很重要,一种选择是只使用一次由 Module 创建的持久性局部变量。如果即使这个开销很大,我也会重新考虑设计 - 从那时起显然你的函数做得太少了。在某些情况下 Block
更有益,例如当你想确保局部变量使用的所有内存都将是自动释放(这与 DownValues
的局部变量特别相关,因为它们在由 Module
创建时并不总是被垃圾收集)。使用 Block
的另一个原因是当您预计可能会出现异常或中止等中断,并希望自动重置局部变量(Block
会这样做)。但是,使用 Block
会冒名称冲突的风险,因为它动态绑定(bind)变量而不是词法绑定(bind)。所以,总结一下:在大多数情况下,我的建议是这样的:如果你觉得你的函数有严重的内存或运行时效率低下,那就看看别处——作用域构造成为主要瓶颈的情况很少见。异常(exception)情况包括没有垃圾收集的
Module
变量和累积数据、非常频繁使用的轻量级函数,以及在非常高效的低级结构(如压缩数组和稀疏数组)上运行的函数,其中符号范围开销可能与函数处理其数据所花费的时间,因为主体非常高效并且使用绕过主评估器的快速函数。编辑
通过以建议 here 的方式组合
Block
和 Module
:Module[{xl}, fmbp[x_] := Block[{xl = x}, xl]]
您可以两全其美:一个功能与
Block
一样快 - 范围内的功能和使用 Module
的功能一样安全。
关于wolfram-mathematica - 条件、 block 、模块 - 哪种方式内存和计算效率最高?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7596460/