Sjo*_*ies 9 memory-management wolfram-mathematica
我需要在一长串对中找到所有数字对的总和.在Mathematica中有很多方法可以做到这一点,但我正考虑使用其中任何一个Plus或Total.由于Total在列表上工作,Map是在那里使用的函数式编程工具,Apply在级别1(@@@)是要使用的Plus,因为Plus要将数字作为参数添加.
这是一些演示代码(警告:在执行此操作之前保存所有工作!):
pairs = Tuples[Range[6000], {2}]; (* toy example *)
TimeConstrained[Plus @@@ pairs; // Timing, 30]
(* Out[4]= {21.73, Null} *)
Total /@ pairs; // Timing
(* Out[5]= {3.525, Null} *)
Run Code Online (Sandbox Code Playgroud)
您可能已经注意到我已添加TimeConstrained到代码中Plus.这是我为你提供的保护措施,因为裸代码使我的PC几乎瘫痪.事实上,上面的代码对我有用,但如果我将第一行的范围增加到7000,我的计算机就会锁定并且永远不会回来.什么都行不通,没有alt-period,程序切换,ctrl-alt-delete,尝试使用任务栏启动进程管理器,关闭笔记本电脑盖让它睡觉等等,真的没什么.
问题是由Plus @@@ pairs线路的极端内存使用引起的.虽然'对'本身占用大约288 MB,而总数的一半,但Plus系列的计算速度很快消耗约7 GB.这是我的免费物理内存的结束,任何更大的内容都会导致在磁盘上使用虚拟内存.当使用虚拟内存时,Mathematica和/或Windows显然效果不佳(BTW,MacOS和Linux表现更好吗?).相反,Total行对内存使用情况图没有明显影响.
我有两个问题:
Plus和(Total如[Total]列表相当于Apply [Plus,list].)如何解释行为的极端差异?我认为这与之间的差异做Apply和Map,但我很好奇,所涉及的内部机制.MemoryConstrained,但是如果您怀疑Mathematica可能会占用您的所有系统资源,那么必须在任何地方使用它是一件痛苦的事.是否有一个全局设置可以告诉Mathematica仅为其所有操作使用物理内存(或者,最好是其中的某一部分)?这将是非常有帮助的,因为这种行为导致了过去几周的一些锁定,并且它真的开始惹恼我.Plus@@@pairs 打开包装:
In[11]:= On["Packing"]
In[12]:= pairs=Tuples[Range[6000],{2}];
In[13]:= TimeConstrained[Plus@@@pairs;//Timing,30]
During evaluation of In[13]:= Developer`FromPackedArray::punpack1: Unpacking array with dimensions {36000000,2}. >>
Out[13]= $Aborted
Run Code Online (Sandbox Code Playgroud)
这将做同样的事情,不解包,这意味着它使用更少的内存.
On["Packing"]
pairs=Tuples[Range[6000],{2}];
a = pairs[[All, 1]];b=pairs[[All, 2]];
Plus[a, b];
Run Code Online (Sandbox Code Playgroud)
您可以在此处阅读有关Mathematica包装的更多信息:http: //www.wolfram.com/technology/guide/PackedArrays/
我只是想补充一些可能会更清楚地澄清情况的观察结果.正如@Joshua的回答中所指出的那样(参见本文对类似讨论的评论),效率低下的原因与解包有关.我的猜测是,为什么一般的原因Apply解压是编译器(Compile)有一个非常有限的支持Apply-即只能使用3头- List,Plus和Times.出于这个原因,在中SystemOptions["CompileOptions"],我们可以看到编译长度Apply设置为无穷大 - 一般来说,甚至尝试自动编译都没有意义Apply.然后可能,当编译长度大于实际数组维度时,它会解压缩.当我们将其设置"ApplyCompileLength"为有限长度时,行为确实会发生变化:
On["Packing"]
pairs=Tuples[Range[2000],{2}];
SetSystemOptions["CompileOptions"->"ApplyCompileLength"->100];
TimeConstrained[Plus@@@pairs;//Timing,30]
{0.594,Null}
Run Code Online (Sandbox Code Playgroud)
再次更改它会恢复观察到的初始行为:
In[34]:=
SetSystemOptions["CompileOptions" -> "ApplyCompileLength" -> Infinity];
TimeConstrained[Plus @@@ pairs; // Timing, 30]
During evaluation of In[34]:= Developer`FromPackedArray::punpack1: Unpacking
array with dimensions {4000000,2}. >>
Out[35]= {2.094, Null}
Run Code Online (Sandbox Code Playgroud)
关于你的第二个问题:或许,约束内存的系统方法与@Alexey Popkov所做的一致,就是使用主内核来控制内存不足时重启的从内核.我可以提供一个远不那么复杂但可能仍然有用的黑客.以下功能
ClearAll[totalMemoryConstrained];
SetAttributes[totalMemoryConstrained, HoldRest];
Module[{memException},
totalMemoryConstrained[max_, body_, failexpr_] :=
Catch[MemoryConstrained[body,
Evaluate[
If[# < 0, Throw[failexpr, memException], #] &@(max -
MemoryInUse[])], failexpr], memException]];
Run Code Online (Sandbox Code Playgroud)
将尝试约束内核使用的总内存,而不仅仅是在给定的特定计算中.因此,您可以尝试将其包装在顶级函数调用周围,只需执行一次.因为它依赖于MemoryConstrained和MemoryInUse,这只是因为他们是那么好.有关如何使用它的更多详细信息,请参阅此 Mathgroup文章.您可以使用$Pre它自动将此应用程序应用于您的输入,并减少样板代码的数量.
| 归档时间: |
|
| 查看次数: |
909 次 |
| 最近记录: |