【问题标题】:Don't check variable every iteration不要每次迭代都检查变量
【发布时间】:2016-08-19 04:19:40
【问题描述】:

我目前有一个for-loop,它正在经历大量的迭代来检查某些东西,当它进入新的迭代时,我需要它来检查我拥有的变量是否与当前迭代。
这是我正在做的示例代码:

import datetime
now = datetime.datetime.now()
printcounter = 0
for i in range(3,100000000000+1,2):
     if (printcounter == 1000000000):
          print(i,"at %d" %now.hour, "hours and %d"  % now.minute, "minutes.")
          printcounter = 0
     else:
          #Do operation
          printcounter += 1

但是,由于在我得到答案之前它可能要经过数百万次数学繁重的运算,我注意到通过剥离“printcounter”变量的这段代码而不给我进度报告,我的速度显着加快了整整几分钟有时。

有没有办法只检查 'printercounter' 变量是否等于 10000,而不检查每一次 迭代?
如果不使用嵌套 for 循环,我个人无论如何都想不出来,这会变得很脏,我宁愿没有。

顺便说一句,我使用的是 Windows 8.1、Python 3.5.1,如果这有什么不同的话。

编辑:
我知道打印需要花费大量时间,但是,如果我改为打印到文件;我的硬盘非常快,然后我仍然得到相同的,虽然减少了,时间差异。另外,我一直想在很多其他脚本中实现这个解决方案,所以即使这不是一个主要问题,我仍然想知道如何去做。

编辑 2:
也许是我的错,没有说清楚。我想看看是否可以每隔一段时间检查一个值,而不是每次都检查一次。例如,我不希望我的代码在 1 时检查 'printcounter' 是否等于 1000000000,这太荒谬了。我知道机器运行得快得离谱,所以没关系,但我很好奇是否有可能减少以这种方式检查的次数,而不是拥有一个让自己马虎或懒惰的愚蠢代码只是因为它足够快来纠正它。

【问题讨论】:

  • if 声明不是您的麻烦的原因。您可以通过profiling your Python code 亲自查看此内容,这样您就知道程序的哪些部分真正花费了最多时间。
  • 你真的要打印这10,000,000个中间进度报告吗? O_o
  • @Reblochon Masque 它不会打印所有内容,只是每 10000 次迭代它都会给我一个状态检查。
  • 是的,10,000,000 = 100,000,000,000 / 10,000,这就是我问的原因!照原样,您的设置将打印 1000 万条“状态检查”行!
  • @Reblochon Masque 嗯...哎呀。这不是我的主要程序,我是在一个单独的环境中开发的,我没有想太多就设置了数字,但那是一个令人印象深刻的地方,这可能是在不同情况下速度变慢的原因,我'现在就换个问题。

标签: python performance python-3.x variables for-loop


【解决方案1】:

如果您不想每次迭代都检查变量,那就让它变得不必要...
改为这样做:

import datetime

iterations = 100000000000
subiterations = 10000
chunks, remaining = divmod(iterations, subiterations)

now = datetime.datetime.now()
printcounter = 0
for i in range(chunks):
    for j in range(subiterations):
        #Do operation
        pass

    printcounter += subiterations
    print('{:,d} at {} hours {} minutes'.format(printcounter, now.hour, now.minute))

if remaining:
    for j in range(remaining):
        #Do operation
        pass

    printcounter += remaining
    print('{:,d} at {} hours {} minutes'.format(printcounter, now.hour, now.minute))

【讨论】:

  • 你是怎么做到的?你的速度也快得离谱。
  • “诀窍”是使用内置的divmod 函数来计算(a // b, a % b) 来确定变量会增加 的次数(在执行@987654326 之后@),然后每次完成时就增加一次。
  • 整洁:我在考虑链式迭代器的思路,在“块”之间产生一些打印触发器,但这更简单更好。我在偷它!
  • 另外,每次i 循环迭代执行printcounter += subiterations 是否比在打印中使用i * subiterations 更快? (我不认为两者之间有任何显着差异。只是想知道。)
  • @Jérôme:从技术上讲,我希望进行chunk 加法而不是相等数量的乘法运算会更快——而且无论如何,差异完全是微不足道的。使用timeit 模块通常可以自己回答 Python 速度问题。此外 (;-),它是学习如何使用的非常有用的工具。
【解决方案2】:

加速不是因为检查了那个变量。这是因为 print 语句本身。所以不,除了删除该语句之外,没有其他方法可以进一步加快速度。

并明确回答您的具体问题:您可以重组您的代码,以便不必进行检查,例如,使用嵌套的 for 循环。但这可能会更慢。检查一个布尔比较是否非常小所花费的时间。

【讨论】:

  • 我知道它非常小,但是将它乘以一百万次它必须检查并且它开始变得明显。
【解决方案3】:

既然printcounter 在每次迭代时都会递增,为什么不使用嵌套的 for 循环呢?

大概是这样的:

import datetime
now = datetime.datetime.now()

for j in range(100):
    print(j, "at %d" %now.hour, "hours and %d"  % now.minute, "minutes.")
    for i in range(1000000000):
          #Do operation

【讨论】:

  • 这很有趣,但是双 for 循环显着减慢了进程。
  • range(3,100000000000+1,2 / 10000) 引发 TypeError
  • 是的,我提供这个示例只是为了说明嵌套循环的概念。我没有测试它,事实上,我忽略了那部分。
  • 好吧,我想您确实说过“大致像这样”并且一个可以编写他们自己的接受浮点参数的frange() 函数/类(尽管它会是由于计算机浮点数学问题而变得棘手)。无论如何,您的代码仍然会很慢,因为如果它有效,由于内部和外部 for 循环的参数值(不仅仅是因为它使用了嵌套配对)。
  • 嗯...当然。参数由他决定,作为速度和反馈之间的权衡。同样,这个想法只是为了说明嵌套循环是什么,仅此而已。我把它们改成了更快的东西(反馈更少),因为这可能只对我很明显。无论如何,感谢您确认我没有遗漏其他内容。
【解决方案4】:

这不会有太大区别,因为与实际的 print 语句相比,int 数学很小,但是:

import datetime


now = datetime.datetime.now()
step = 2
init = 3
for i in range(init, 100000000000+1, step):
    if (i % 10000*step) == init:  #since we start at 3 and step by 2
         print(i,"at %d" %now.hour, "hours and %d"  % now.minute, "minutes.")
    # Do Stuff

这种结构会消除一些操作,但它们都不是慢操作。但就代码结构而言,这就是我的做法。

【讨论】:

  • xrange == range - 这是python 3
  • 啊,原来如此。我会解决的。
猜你喜欢
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
相关资源
最近更新 更多