2016-03-04 135 views
5

這是什麼我談論的是一個基本的例子:Python中,計算計算的狀態減慢計算本身

計數從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秒。有沒有辦法解決這個問題?我發現了一些線程和多進程,但我無法弄清楚如何實現它。謝謝

+0

沒有試過這個實現,但會像這樣的工作? https://docs.python.org/2/library/threading.html#timer-objects – Tom

+0

也許你可以將計算包裝到某種「Task」類中,並讓另一個線程定期檢查該任務的狀態。雖然有點模糊。 –

+0

取決於處理器。你有多少核心?我試圖第二個例子上一個imac,它顯示輸出'39.0 79.0 2.53144' 我想這花了2.53s – pbu

回答

2

標杆

我寫了不同的解決方案並加以比較。我需要將你的價值乘以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類

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() 
+0

對不起,這可能是一個愚蠢的問題,但我該如何運行它? – Matteo

+0

不錯,我會稍後再試,並提供反饋,謝謝 – Matteo

+0

我會很感激一些反饋意見。 – DreyFax

1

如果您使用的是類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