我正在阅读a useful post at WRI blog on improving speed of code,我需要帮助才能理解这一点。
比较这些速度
Timing[
tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];
]
{0.031, Null}
和
Timing[
a = 1000;
tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
]
{0.422, Null}
因此,当将表中的限制的实际值与外部相比时,它会快得多。对此的解释,我确信它是正确的,但我需要帮助理解,如果Table
的限制是数字而不是数字,则编译HoldAll
,这是因为它的属性是Table
。
但我的问题是:上述实际上会如何运作,因为Clear[a]
tbl = Table[i + j, {i, 1, a}, {j, 1, a}]
的限制必须在某一时刻成为数字?我不能写
a=1000
上面给出了错误。
所以,对我来说,在Table
与内部之间写a
应该没有区别,因为如果Table[]
没有数值,a
就不能做任何事情。因此,在Table[]
可以做任何有用的事情之前,评估者必须在一个时间点替换Table
,不是吗?
换句话说,{i, 1, 1000}, {j, 1, 1000}
最终应该看到的是a
两种情况。
所以,我认为这种情况会发生的方式是:
Table
替换为1000
HoldAll
,结果现在全部为数字。但似乎发生的事情是别的。 (由于a
?)
a
而不是1000。a
限制的表,Evaluator评估Compile
为1000 问题是:上述情况会发生什么?有人可以解释为解释这种时间差异而发生的步骤吗?
另外,在上面的例子中,如何确保表格在两种情况下都被编译,即使一个人使用变量作为限制?并不总是可以对表限制的数字进行硬编码,但有时必须使用变量。是否应该明确使用Compile
命令? (我不直接使用ClearAll[tblFunc];
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tblFunc[a]]
]
,因为我认为它是在需要时自动完成的。
修改(1)
在回答Mike的帖子时,发现使用电话的时间没有差异。
{0.031, True}
给出
a
但这是因为1000
现在是函数的a
数字,一旦调用它。由于M通过VALUE传递东西。
如果我们强制通过引用进行调用,以便ClearAll[tblFunc];
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tblFunc[Unevaluated@a]]
]
未被评估,那么我们就会
a
现在我们看到了预期的结果,因为现在{0.437, False}
仍然是符号INSIDE函数,我们回到原点,现在它很慢,因为没有打包。由于它没有打包,因此不使用编译。
{{1}}
修改(2) 感谢大家的答案,我想我是从他们那里学到的。
这是一份执行摘要,只是为了确保我把一切都搞定。
修改(3)
以下链接我特别关注用于使Mathematica代码运行得更快的提示。
答案 0 :(得分:16)
所以这就是我认为正在发生的事情。您在Table
上看到数字和符号限制之间的减速的原因是由于您执行双索引。每个子表(例如,遍历所有索引j
以获得固定索引i
)是单独构造的,当限制是符号时,在构造每个子表之前需要额外的步骤来确定该限制。您可以通过检查,例如,
Trace[a = 3;
tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
]
David给出了一个很好的例子,说明为什么要对每个子列表进行此检查。至于为什么 Mathematica 无法弄清楚何时不需要这项检查,我不知道。如果只有一个索引可以求和,那么符号和数字版本之间的速度没有区别
Timing[tbl = Table[i + j, {j, 1, 1000}];]
{0.0012, Null}
Timing[a = 1000;
tbl = Table[i + j, {j, 1, a}];
]
{0.0013, Null}
回答有关速度的跟进;使tbl
函数对数字和符号限制都更快。
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
tblFunc[a];
]
{0.045171, Null}
VS
Timing[tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];]
{0.066864, Null}
Timing[a = 1000;
tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
]
{0.632128, Null}
如果您打算重复使用tbl
构造,可以获得更快的速度。
b=1000;
Timing[tblFunc[b];]
{0.000013, Null}
答案 1 :(得分:3)
正如其他人所提到的,要监控的关键事项是打包和列表长度。我实际上没有看到蒂莫报告的差异:
ClearAll[tblFunc];
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tblFunc[a]]]
{0.077706, True}
vs
ClearAll[tbl];
Timing[
tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];
Developer`PackedArrayQ[tbl]]
{0.076661, True}
ClearAll[tbl];
Timing[a = 1000;
tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tbl]]
{1.02879, False}
所以对我而言,唯一的区别是列表是否已打包。它是否是一个功能对我的设置时间没有任何影响。正如预期的那样,当您关闭自动编译时,上述所有时间都是相同的,因为没有打包:
SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> Infinity}];
{1.05084, False}
vs
{1.00348, False}
{1.01537, False}
重置表自动编译长度:
SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> 250}]
答案 2 :(得分:2)
这有点OT,但是为了提高速度,您可能希望避免使用在使用Table时隐含的逐项处理。相反,使用外部。这是我在我的系统上看到的内容:
Timing[Outer[Plus, Range[5000], Range[5000]];]
{0.066763,Null}
Timing[Table[i + j, {i, 1, 5000}, {j, 1, 5000}];]
{0.555197,Null}
相当显着的差异。