【问题标题】:Python, calculating the status of computation slows down the computation itselfPython,计算计算状态会减慢计算本身
【发布时间】:2016-06-18 02:13:36
【问题描述】:

这是我所说的一个基本示例:

从 0 到 10000000 计数

import time

k = 0

beginning = time.time()

while k < 10000000:

    k = k+1

elapsed = round(time.time()-beginning, 5)

print (elapsed)

现在有了一种计算的“状态”(每 1 秒显示一次百分比):

import time

k = 0

beginning = time.time()
interval = time.time()

while k < 10000000:

    if time.time() - interval > 1:
        print (round((k/100000), 5))
        interval = time.time()

    k = k+1

elapsed = round(time.time()-beginning, 5)

print (elapsed)

第一个示例耗时 3.67188 秒,第二个示例耗时 12.62541 秒。我想这是因为脚本必须不断检查是否已经过了 1 秒。有没有办法解决这个问题?我发现了一些关于线程和多进程的东西,但我不知道如何实现它。谢谢

【问题讨论】:

  • 没有尝试过这个实现,但是这样的东西会起作用吗? docs.python.org/2/library/threading.html#timer-objects
  • 也许你可以将计算包装到某种Task 类中,并让另一个线程定期检查该任务的状态。不过有点模糊。
  • 取决于处理器。你有几个核心?我在 imac 上尝试了第二个示例,它显示输出 39.0 79.0 2.53144 我认为它花了 2.53 秒

标签: python performance computation


【解决方案1】:

基准测试

我编写了不同的解决方案并进行了比较。我需要将您的值乘以 10 才能获得可衡量的结果。首先没有任何进度测量,看看它在我的机器上运行得有多快。

def process_without_measuring(self):
    self._start = time.time()

    self._k = 0
    while self._k < 100000000:
        self._k = self._k+1

    print (time.time() - self._start)

我得到 13.8 秒的持续时间。

让我们从你的实现开始:

def process_with_original_measuring(self):
    self._start = time.time()
    next = self._start
    self._k = 0
    while self._k < 100000000:
        self._k = self._k+1
        if time.time() - next > 1:
            print (round((self._k / 1000000), 5))
            next = time.time()

    print("duration:")
    print (time.time() - self._start)

如果我运行它,我会得到 30.31 秒 的持续时间,并且每秒增加大约 3%。问题是它必须比较每个循环运行的时间并进行算术运算。您可以通过将循环更改为:

def process_with_manual_measuring(self):
    self._start = time.time()
    next = self._start + 1
    self._k = 0
    while self._k < 100000000:
        self._k = self._k+1
        if time.time() > next:
            print (round((self._k / 1000000), 5))
            next = time.time() + 1

    print("duration:")
    print (time.time() - self._start)

我没有在每个循环中减去时间戳,而是只计算下一个时间戳并与之进行比较。这当然不是很快,但比以前更快。它让我达到了 22.0 秒,因此只需删除这一项操作即可节省 8 秒。

使用计时器对象作为线程可以获得更好的结果,这是更可取的方式:

def show_progress(self):
    print (round((self._k / 1000000), 5))
    self._timer = Timer(1, self.show_progress)
    self._timer.start()

def process_with_timer(self):
    self._start = time.time()
    self._timer = Timer(1, self.show_progress)
    self._timer.start()
    self._k = 0
    while self._k < 100000000:
        self._k = self._k+1
    self._timer.cancel()

    print("duration:")
    print (time.time() - self._start)

运行此程序,我每秒获得 7% 的输出,并在 13.8 秒后完成。如您所见,没有区别。只需要再打几个电话,而且这些电话几乎很快就完成了。

如何使用计时器类

Timer 的构造函数需要一个以秒为单位的持续时间以及一个在时间过去后调用的方法。您可以使用类方法、函数或 lambda 表达式。构建完成后,您需要使用start() 启动计时器。

第一个计时器由进程本身启动。在此之后,每次调用计时器都会启动一个新计时器以获取一秒的间隔。当进程完成时,记得在计时器上调用cancel()。否则它将无限运行,因为它会每秒重新启动。

如何运行示例

请注意以上方法是类方法,请注意缩进。

import time
from threading import Timer

class ProgressMeter:
    def __init__(self):
        self._k = 0
        self._timer = 0

    # insert above methods with indentation as same level as __init__(self):

要运行它们,您只需要创建一个 ProgressMeter 实例并调用您想要的方法。

meter = ProgressMeter()
meter.process_with_timer()

【讨论】:

  • 对不起,这可能是一个愚蠢的问题,但我该如何运行呢?
  • 很好,我稍后会尝试并提供反馈,谢谢
  • 我将不胜感激。
  • 对不起,我接受了答案。您提供的解决方案很好,我用各种算法对其进行了测试,似乎有了很大的改进。我计算出它会减慢 15%(但是我只尝试了 1 台机器)。
【解决方案2】:

如果您使用的是类 Unix 系统,则可以使用 signal 模块中的 signal.alarm

下面的代码有点乱,但是你可以通过将东西封装在一个类中来使它更整洁。

import time
import signal

# Alarm delay in seconds. Must be an integer.
alarm_delay = 1

def handler(signum, frame):
    report()

    # Request a new SIGALRM signal
    signal.alarm(alarm_delay)

# Set a handler for the SIGALRM signal
signal.signal(signal.SIGALRM, handler)

# Request the initial SIGALRM signal
signal.alarm(alarm_delay)

# Report current progress
def report():
    print(round(k / 100000, 5))

k = 0
beginning = time.time()
while k < 10000000:
    k = k + 1

elapsed = round(time.time() - beginning, 5)
print (elapsed)

# Cancel the pending alarm
signal.alarm(0)

典型输出在我的 2GHz 机器上。

18.90911
35.98427
50.17902
64.53358
83.42723
5.94397

【讨论】:

    猜你喜欢
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多