Benchmarking
I wrote different solutions and compared them. I needed to multiply my value by 10 to get measurable results. First, without any measure of progress, to find out how fast it works on my machine.
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)
I get a duration of 13.8 seconds .
Start with your implementation:
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)
If I run this, I get a duration of 30.31 seconds and about 3 percent per second. The problem is that it must compare the time of each cycle and perform an arithmetic operation. You can reduce the time by changing the loop to:
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)
Instead of subtracting the timestamps of each cycle, I calculate the next timestamp only once and compare it. This, of course, is not very fast, but faster than before. This gives me 22.0 seconds , therefore saving 8 seconds with just deleting this one operation.
With a timer object as a stream, you get a much better result, and this is the preferred way:
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)
By running this, I get 7% more output every second, and this is done after 13.8 seconds . As you can see, there is no difference. There are not so many requests, and this is done almost immediately.
How to use a timer class
The Timer
constructor expects the length of time in seconds and the method to call after the time has passed. You can use a class method, function, or lambda expression. After building you need to start the timer using start()
.
The first timer is started by the process itself. After that, each time the timer is called, a new timer starts to get an interval of one second. When the process ends, remember to call cancel()
on the timer. Otherwise, it will work endlessly because it will restart every time.
How to run examples
Note that the above methods are class methods, so see the indentation.
import time from threading import Timer class ProgressMeter: def __init__(self): self._k = 0 self._timer = 0
To run them, you need to create an instance of ProgressMeter and call the method you want.
meter = ProgressMeter() meter.process_with_timer()