【发布时间】:2012-01-03 07:33:03
【问题描述】:
我正在阅读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}]
上面给出了一个错误。
所以,对我来说,在Table 和内部写a=1000 应该没有区别,因为没有a 有一个数值,Table[] 不能做任何事情。因此,在 Table[] 可以做任何有用的事情之前,评估者必须在某个时间点将 a 替换为数字 1000,不是吗?
换句话说,Table 在这两种情况下最终应该看到的是{i, 1, 1000}, {j, 1, 1000}。
所以,我认为这会发生的方式是这样的:
- Evaluator 将表参数中的
a替换为 1000 - 评估员调用
Table并得到结果,现在全是数字。 - Table 已编译,现在运行速度更快。
但似乎发生的事情是另一回事。 (由于HoldAll?)
- 表按原样接受它的参数。因为它有 HoldAll,所以它看到
a而不是 1000。 - 它不调用 Compile,因为它的参数并非全是数字。
- 它现在生成一个带有
a限制的表,Evaluator 将a评估为 1000 - 现在已生成表,所有限制都是数字,但现在速度较慢,因为未编译代码。
问题是:会发生上述情况吗?有人能解释一下解释这种时间差异的步骤吗?
另外,在上面的例子中,如何确保 Table 在两种情况下都被编译,即使使用一个变量作为限制?并非总是可以硬编码表格限制的数字,但有时必须为这些数字使用变量。是否应该明确使用Compile 命令? (我不直接使用Compile,因为我认为它是在需要时自动完成的。
编辑(1)
在下面 Mike 发表的关于使用呼叫时发现时间没有差异的回答中。
ClearAll[tblFunc];
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tblFunc[a]]
]
给予
{0.031, True}
但那是因为a 现在是函数内部的数字1000,一旦它被调用。由于 M 通过 VALUE 传递事物。
如果我们强制调用是通过引用进行的,这样a 就不会被评估,那么我们得到
ClearAll[tblFunc];
Timing[a = 1000;
tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
Developer`PackedArrayQ[tblFunc[Unevaluated@a]]
]
现在我们看到了预期的结果,因为现在a 在函数内部仍然是符号,我们回到第一方,现在它很慢,因为没有打包。而且由于没有打包,所以没有使用Compile。
{0.437, False}
编辑(2) 感谢大家的回答,我想我从他们那里学到了分配。
这是一个执行摘要,只是为了确保我一切正常。
编辑(3)
以下是我专门提供的与使 Mathematica 代码运行得更快的提示相关的链接。
【问题讨论】:
-
请注意,您可以使用
Table[i + j, {i, 1, 1000}, {j, 1, i}]之类的东西,这是当限制不是全部数字时不预编译Table的原因。 -
@David 我同意你的说法,只是想强调一下,
Table对于符号迭代器来说很慢的真正原因似乎是它无法确定结果是否会是 rectangular 数组,因此不能使用压缩数组。它不能使用Compile的事实由此而来——因为打包数组是Compile效率提升的原因(至少在编译为 MVM 目标时,我认为这是在自动编译中发生的)。 -
另一个有趣的观察:
Timing[Table[i + j, {i, Range[5000]}, {j, Range[5000]}];]似乎也未编译,可能出于相同的原因。然而,在这里,唯一实用的内联选项是使用With,如With[{rr = Range[5000]}, Table[i + j, {i, rr}, {j, rr}]];。输入 5000 个值作为输入单元格不是很实用... -
一个很好的问答。节省了我很多时间在未知中徘徊。在@Nasser Edit(1) 上的一项观察“对于更高维度的表,如果至少一个索引是符号的,则不是打包/慢速”,我发现 它仅在内部索引上是正确的。在给定的示例中,它是外部符号索引,它对我来说仍然很快;一旦改为内部符号索引就会变慢。