【问题标题】:Python takes more time to print a calculation than to perform itPython 打印计算比执行计算花费更多时间
【发布时间】:2014-05-09 23:05:19
【问题描述】:

我用 python 写了一个脚本,这让我很惊讶。 基本上,它需要五个 20 位数字,将它们相乘,然后将它们提高到 3000 的幂。timeit 模块用于查找计算计算所需的时间。好吧,当我运行这个脚本时,它说计算它需要 3*10^-7 秒。 然后它会生成一个文件 output.txt,但脚本直到大约 15 秒后才结束。

import timeit
outputFile = open("output.txt", "w")
start = timeit.default_timer()
x = (87459837581209463928*23745987364728194857*27385647593847564738*10293769154925693856*12345678901234567891)**3000
stop = timeit.default_timer()
time = stop-start
print "Time taken for the calculation was {} seconds".format(time)
outputFile.writelines(str(x))
outputFile.close()
y = raw_input("Press enter to exit.")

这是否意味着打印一个 280kb 的文件实际上比执行计算需要更长的时间?(我觉得不太可能。)

如果不是这样,那么当调用变量 x 时,python 会执行计算吗?是每次计算变量时都执行计算,还是将实际值存储在变量中?

我刚刚编写了另一个脚本,它确认 python 将结果写入 .txt 文件需要 0.03 秒。那么,为什么 python 后面会执行计算呢?

【问题讨论】:

  • I/O 操作(如打印)通常比大多数计算慢。
  • 特别是当您打印的是一个大约 300,000 位长的数字时。
  • 280kb?噗,这没什么吧?嗯,是的。实际上很多。
  • 你可以尝试同样的事情,只是打印到 IDLE 控制台。如果您注释掉打印行并比较速度,很明显问题出在打印而不是计算。这是python世界中一个众所周知的问题。如果 IDLE 控制台中包含大量文本,它有时也会减慢计算机的其他任务。

标签: python performance variables numerical-computing


【解决方案1】:

问题不在于计算,也不在于写入文件:将结果从其内部二进制表示转换为 base-10 表示消耗了大量时间。这需要与位数成二次方的时间,而您这里有很多位。

如果您将输出行替换为:

outputFile.writelines(hex(x))

您会发现它运行得非常快。转换为十六进制表示只需要与位数成线性关系的时间。

如果您确实需要以 10 为基数输出大整数,请考虑改用 decimal 模块。这在内部以与基数 10 相关的表示形式进行计算,然后转换为十进制字符串需要与十进制位数成线性关系的时间。不过,您需要提前将小数上下文的精度设置为“足够大”的值,以避免因舍入而丢失低位数字。

【讨论】:

  • +1 表示它可能是O(ndigits**2)。你能详细说明为什么long_to_decimal_string() 是二次的吗? (我在PyLong_FromString()看到了相应的评论,但方向相反)。
  • 因为 Python long 内部存储在(基本上)基数 2**15 中,并且 CPython 并没有做出英勇的努力来使用 2 次幂和 2 次幂之间的次二次基转换算法10个基地。它使用或多或少明显的(和二次时间)算法(“一次输出一个数字”)。
  • 关于使用十进制:确保您使用的是 Python >= 3.3,或者使用来自 PyPI 的 cdecimal 包。否则,计算仍以二进制进行,并且二进制 十进制转换在大数的运算时间中占主导地位。 (所以在 Python 2.7 中,小数加法需要的时间是位数的二次方!)
【解决方案2】:

转换成字符串需要这么长时间:

In [68]: %time x = (87459837581209463928*23745987364728194857*27385647593847564738*10293769154925693856*12345678901234567891)**3000
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s

In [69]: %time xs = str(x)
CPU times: user 1.98 s, sys: 0.00 s, total: 1.98 s
Wall time: 1.98 s

In [71]: %time print xs
CPU times: user 0.01 s, sys: 0.00 s, total: 0.01 s
Wall time: 0.04 s

但是对于具有数十万位数的数字应该不足为奇。

编辑

与其他答案相反,写入文件不需要太多时间:

In [72]: %time with open('tmp.file', 'w') as f: f.write(xs)
CPU times: user 0.00 s, sys: 0.01 s, total: 0.01 s
Wall time: 0.00 s

【讨论】:

  • 尝试将幂设为变量:n=3000; (..)**n
  • 计算当然要慢得多,但仍然比 str(x) 快得多。我应该从中得到什么?
【解决方案3】:

除其他答案外,请使用outputFile.write(str(x)) 而不是writelines。 writelines 旨在与一系列字符串一起使用。在您的情况下,它会迭代字符串并单独写入每个字符。在一个简单的测试中,writelines 慢了 3.7 倍:

>>> timeit("f.writelines(str(s))", setup="f=open('tmp.txt','w');s=range(1000)", number=10000)
4.935087700632465
>>> timeit("f.write(str(s))", setup="f=open('tmp.txt','w');s=range(1000)", number=10000)
1.3468097837871085

【讨论】:

  • +1。在我的机器上,计算数字需要 0.0184 μs,将其转换为字符串 (str(x)) 需要 3500000 μs,将其写入文件 (.write()) 需要 114 μs,.writelines() 需要 10200 μs。换句话说,str(x) 主宰一切
  • 更正:计算数字需要50000微秒(似乎Python编译器计算了一些文字,即如果任何数字是变量,则先前的结果不正确)
  • @J.F.Sebastian,这就是“除了...”部分的全部内容。它不是主要的减速,但也应该修复。
  • 我知道,这就是上面+1的原因。
猜你喜欢
  • 1970-01-01
  • 2014-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多