【问题标题】:using print in loop slows down the loop在循环中使用打印会减慢循环速度
【发布时间】:2019-02-20 14:58:39
【问题描述】:

在循环中使用print 会减慢循环速度。打印一些东西(我试过Hello! 100 次需要大约 2 秒,没有它,需要 0.0 秒。我使用模块time 准确地记录了时间。这是一个在其中打印并显示最后花费的时间的循环:

import time

t = time.time()
for _ in range(100):
    print("Hello! ",end = "")

print("\n",time.time()-t)

输出:

Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! 
 1.9912450313568115

这是另一个循环,它只是将字符串添加到变量中,需要 0.0 秒

import time

t = time.time()
output = ""
for _ in range(100):
    output += "Hello! "

print(time.time()-t)

输出:

0.0

我尝试添加更多操作,但它仍然需要0.0 秒。示例:

import time

t = time.time()
output,num,count,abc = "",0,30,"H"
for _ in range(100):
    output += "Hello! "
    num += 10000
    count += 10000000
    abc += "Hello Guys!"

print(time.time()-t)




为什么print 会减慢循环速度,我该如何解决这个问题?

【问题讨论】:

  • 你不能。 IO 很慢。您可以将所有输出存储在一个列表中,并在最后print(*myOutputs, sep="\n") 它们 - 这将减少循环将字符串插入到列表中所花费的时间。仍然需要一些时间,但稍微少一点 - 除非您在存储所有输出时遇到内存问题。简洁的岩石;)
  • 也用于性能测试,我会使用类似 timeit:docs.python.org/3/library/timeit.html 的东西 - 它将执行代码 10000 次并在测量事物时平均异常值。
  • 答案是不要将print() 放在一个循环中。通常无论如何它是没有意义的,只是一个压倒性的流。如果您想监控进度,请使用 if loop_count % 1000 == 0: print(something)
  • 还有 2:不要添加到字符串中,它们是不可变的——你一直在重建新的字符串。使用列表来存储字符串部分和''.join(parts) 以后。
  • 这就是我建议模数的原因

标签: python python-3.x time


【解决方案1】:

print() 会减慢你的循环速度。那是因为每次调用 print() 时都在进行系统调用和 IO 操作。系统调用会消耗大量 CPU 周期并涉及 CPU 上下文切换。 IO 操作会阻塞你进程的主线程一段时间。

因此,显而易见的解决方案是消除或减少 print() 调用的次数。

如果你真的需要一种机制来知道当前循环的迭代次数,那么你可以使用多线程来实现这一点。但是,它仍然可能涉及系统调用和线程上下文切换。但我想它仍然会比 print() 快。

诀窍是在后台线程中执行循环,同时在主线程中打印进度。这样调用 print() 的 IO 操作不会阻塞运行循环的线程。为了进一步优化它,您可以仅在用户按键时打印进度。

import threading

lock = threading.Lock()
count = 0

def your_method_with_a_loop():
    global count
    with open("f.txt","w") as f:
        for q in range(1000000):
            f.write(str(q)+"\n")
            #your_logic_here
            #....
            lock.acquire()
            count = count + 1
            lock.release()

#Run the loop in a background thread
t1 = threading.Thread(target=your_method_with_a_loop)
t1.start()

while t1.isAlive():
    print("Press enter to see current loop iteration count\n")
    #use raw_input() instead if your are using python 2.x.
    input() #Remove this line if you want to print progress continuously.
    lock.acquire() 
    current_count = count
    lock.release()
    print("Current loop iteration count is ",count,"\n")

此解决方案通过两种方式改善了这种情况

  1. IO 操作不在工作线程上执行。是的,使用锁涉及系统调用。但它仍然比 IO 块快。

  2. 假设 python 解释器使用futex 来实现锁,那么获取和释放锁的成本非常慢,因为与工作线程相比,主线程很少持有锁。

【讨论】:

  • 我没有看到这如何缓解这个问题?现在你可以设置锁了
  • @roganjosh 它通过两种方式改善了这种情况 1. IO 操作不在运行循环的线程上执行。是的,使用锁涉及系统调用。但它仍然比 IO 块快。 2.假设python解释器使用futex来实现锁,那么锁几乎是一个免费的操作,与工作线程相比,主线程很少持有锁。
  • 当我回到 PC 时我会测试这个 :) 如果你能像这样卸载标准输出会很有趣
  • 这可能是矫枉过正。
  • 不错,我修复了几个代码拼写错误以使其运行 +1 ... ups ,您也开始修复。如果你愿意,可以回滚,你仍然缺少文件写入和函数定义的()
猜你喜欢
  • 2021-11-24
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
相关资源
最近更新 更多