multithreading in python and time module [duplicate] - python

This question already has an answer here:
perf_counter is returning wrong time
(1 answer)
Closed 5 months ago.
I'm trying to learn multi_threading in python but when I try to print time.perf_counter() in order to see how much time the Main Threading takes to run the program which is in charge the output is a huge number (614691.9609577), but it should not even be 2 seconds. Can you explain the reason of this problem?
Thanks
import threading
import time
def have_breakfast():
time.sleep(3)
print("You had breakfast")
def make_bed():
time.sleep(4)
print("You made your bed")
def study():
time.sleep(5)
print("You finish studying")
x = threading.Thread(target = have_breakfast, args = ())
x.start()
y = threading.Thread(target = make_bed, args = ())
y.start()
z = threading.Thread(target = study, args = ())
z.start()
x.join()
print(threading.active_count())
print(threading.enumerate())
print(time.perf_counter())

From here:
time.perf_counter():
Return the value (in fractional seconds) of a performance counter,
i.e. a clock with the highest available resolution to measure a short
duration. It does include time elapsed during sleep and is
system-wide. The reference point of the returned value is undefined,
so that only the difference between the results of two calls is valid.
Use perf_counter_ns() to avoid the precision loss caused by the float
type.
New in version 3.3.
Changed in version 3.10: On Windows, the function is now system-wide.
In your case if you want to measure time you need to subtract two time intervals. E.g.:
t1_start = time.perf_counter()
# your code...
t2_stop = time.perf_counter()
print("Elapsed time: ", t2_stop - t1_start)

Related

Weird problem getting a variable out of a function in Python

What my code does is generate an X amount of random lines, each is the length of X
My program is almost finished but I couldn't get the time to work, more specifically, get it out of the function, I know it calculates the time correctly because if I put a print in the break section it actually prints the time, but when I want to use it outside the function it never is defined
I tried tons of stuff, like globalizing it in the function, outside function (it doesn't change from 0, which means the function is not changing the variable for some reason) , tried float, tried adding the line elapsed = MainCode() , but all never working, I spent like 6 hours with this single issue, 3 of those hours with other programmers from Python's official discord server for extra help, all were also confused as to why is it still not considered defined
here's my full code, any help is appreciated
import random
import string
import multiprocessing
import os
import sys
import time
if __name__ == "__main__":
lines_wanted = input("input how many lines: ") #user can input how many lines he wants
length = input("How long: ") #user can enter how long each line should be
def MainCode(lines_wanted, length):
global elapsed
elapsed = 0.0
starttime = time.time() # start the time
file = open("blablabla.txt", "a",) # open/create the file
i = 0
while 1 == 1:
file.write(''.join(random.choice(string.ascii_letters + string.digits + ".") for i in range(int(length))) + "\n") # write the randomly generated lowercase string
i += 1 * multiprocessing.cpu_count() # count how many lines the loop is on
if i >= int(lines_wanted): # If it reaches the lines it would stop writing
endtime = time.time() # stop the time
elapsed = endtime - starttime #calculate the time
return elapsed
break
processes = []
if __name__ == '__main__':
for _ in range(multiprocessing.cpu_count()):
p = multiprocessing.Process(target=MainCode, args=(lines_wanted, length))
p.start()
processes.append(p)
for process in processes:
process.join()
elapsee = MainCode()
if __name__ == "__main__": # Prints this after finshing the func above
print(f"Finished Writting {lines_wanted} lines, took {elapsee:.1f} to generate")
elapsed is only written by MainCode, which is only called in subprocesses started by multiprocessing.Process. Being in a different process, your main program has no opportunity to observe those variables; unlike threads, subprocesses do not share your namespace. As such, you want to communicate the value somehow. This is conveniently handled by multiprocessing.Pool:
#! /usr/bin/env python3
import multiprocessing
import os
import time
def worker(arg):
starttime = time.time()
time.sleep(3)
endtime = time.time()
return endtime - starttime
if __name__ == '__main__':
wallstart = time.time()
with multiprocessing.Pool() as pool:
times = pool.map(worker, [3]*os.cpu_count())
wallstop = time.time()
print(f'Wall time: {wallstop-wallstart}, worker time: {sum(times)}')
Example run result:
$ python3 multiprocess.py
Wall time: 4.356384515762329, worker time: 24.002115488052368
Of course, the typos others pointed out would keep you from finding the intended variable as well.
One way to know this wouldn't do what you intended is the fact that __name__ must differ between the subprocess and main program. That means it's in a different module, even if they were sharing a process, so they don't share a global namespace.
First, you're trying to print "elapsee" instead of "elapsed".
Second, you probably want to put all the time code outside MainCode completely, instead starting before the process start and the joins, if you want an accurate total elapsed time.

How to precisly sample a sensor-signal in Python [duplicate]

This question already has answers here:
How to repeatedly execute a function every x seconds?
(22 answers)
Closed 4 years ago.
I want to write a Python program that will sample a sensor at a fixed sampling rate. Is there any elegant way of doing this?
Currently, I am using the time.time and time.sleep commands to enforce this manually. While this does work, it is creating a small drift. Also, it seems to be a not very nice way of doing so, and I hope there is a more pythonic way of doing this:
def mock_signal(x):
# Just a random number as the sensor signal
return np.random.random()*x
def sampling(fs=1, x=1):
T = 1/fs # sampling period
t_ground = time.time()
while True:
t_start = time.time()
y = mock_signal(x)
print('%.5f | Sensor Value %.2f' % (t_start - t_ground, y))
t_duration = time.time()
# Sleeping for the remaining period
time.sleep(T - (t_duration-t_start))
Ideally, I would like to have a function or class that would sample the sensor (basically call the 'mock_signal' function) and append the new sample to a list or array. The latest entry in said array should than be accessible by a call similar to the multiprocessings Connection.recv()
Thanks in advance :)
May you can try something like that.
import threading
t_ground = time.time()
def sampling():
t_ground = time.time()
threading.Timer(T, sampling).start()
t_start = time.time()
y = mock_signal(1)
print('%.5f | Sensor Value %.2f' % (t_start - t_ground, y))
It's just an example. You need to change it to your need.

Python : Basic countdown timer & function() > int()

I'm trying to ucreate a timer function that runs in the background of my code and make it so I can use/check the time. What I mean by use/check, I'm trying to make it so I can call upon that timer function and use it as integer.
This is the code I currently have:
def timer():
for endtime in range(0, 15):
print(15 - endtime)
time.sleep(1)
def hall():
timer()
while (timer > 0):
do something
Currently only using print(15 - endtime) for confirmation it is counting down.
But what the code does now is execute the countdown and that's it, it never touches the while loop. And of course the last issue is I can't set a function to an int. So I'm looking for some way where I can check where the timer is at and use it in that while loop.
The way you do it, you'll going to have to use multithread.
Here is another, simpler approach :
On your script beginning, set a time_start variable with the number of seconds since the epoch using time.time()
Then when you need the number of elapsed seconds, use time.time() - time_start :
t_start = time.time()
# do whatever you'd like
t_current = int(time.time()-t_start) # this way you get the number of seconds elapsed since start.
You can put that in a function as well, defining t_start as a global variable.
import time
t_start = time.time()
def timer():
global t_start
print(str(int(time.time()-t_start)))
print('start')
time.sleep(2)
timer()
time.sleep(3)
timer()
import time
def timer(tim):
time.sleep(1)
print tim
def hall():
tim = 15
while (tim > 0):
print 'do something'
timer(tim)
tim-=1
Not the cleanest solution, but it will do what you need.
The problem with your code is that when you run hall(), Python first executes the whole of timer() (i.e. the whole for loop), and then moves on with the rest of the code (it can only do one thing at a time). Thus, by the time it reaches the while loop in hall(), timer is already 0.
So, you're going to have to do something about that timer so that it counts down once, and then it moves on to the do something part.
Something that you can do is this:
def hall():
for a in range(0, 15):
print(15 - a)
# do something
time.sleep(1)
This should work just fine (if you're only executing hall 15 times), and condenses your code to just one function.

Set a timer for running a process, pause the timer under certain conditions

I've got this program:
import multiprocessing
import time
def timer(sleepTime):
time.sleep(sleepTime)
fooProcess.terminate()
fooProcess.join() #line said to "cleanup", not sure if it is required, refer to goo.gl/Qes6KX
def foo():
i=0
while 1
print i
time.sleep(1)
i
if i==4:
#pause timerProcess for X seconds
fooProcess = multiprocessing.Process(target=foo, name="Foo", args=())
timer()
fooProcess.start()
And as you can see in the comment, under certain conditions (in this example i has to be 4) the timer has to stop for a certain X time, while foo() keeps working.
Now, how do I implement this?
N.B.: this code is just an example, the point is that I want to pause a process under certain conditions for a certain amount of time.
I am think you're going about this wrong for game design. Games always (no exceptions come to mind) use a primary event loop controlled in software.
Each time through the loop you check the time and fire off all the necessary events based on how much time has elapsed. At the end of the loop you sleep only as long as necessary before you got the next timer or event or refresh or ai check or other state change.
This gives you the best performance regarding lag, consistency, predictability, and other timing features that matter in games.
roughly:
get the current timestamp at the time start time (time.time(), I presume)
sleep with Event.wait(timeout=...)
wake up on an Event or timeout.
if on Event: get timestamp, subtract initial on, subtract result from timer; wait until foo() stops; repeat Event.wait(timeout=[result from 4.])
if on timeout: exit.
Here is an example, how I understand, what your Programm should do:
import threading, time, datetime
ACTIVE = True
def main():
while ACTIVE:
print "im working"
time.sleep(.3)
def run(thread, timeout):
global ACTIVE
thread.start()
time.sleep(timeout)
ACTIVE = False
thread.join()
proc = threading.Thread(target = main)
print datetime.datetime.now()
run(proc, 2) # run for 2 seconds
print datetime.datetime.now()
In main() it does a periodic task, here printing something. In the run() method you can say, how long main should do the task.
This code producess following output:
2014-05-25 17:10:54.390000
im working
im working
im working
im working
im working
im working
im working
2014-05-25 17:10:56.495000
please correct me, if I've understood you wrong.
I would use multiprocessing.Pipe for signaling, combined with select for timing:
#!/usr/bin/env python
import multiprocessing
import select
import time
def timer(sleeptime,pipe):
start = time.time()
while time.time() < start + sleeptime:
n = select.select([pipe],[],[],1) # sleep in 1s intervals
for conn in n[0]:
val = conn.recv()
print 'got',val
start += float(val)
def foo(pipe):
i = 0
while True:
print i
i += 1
time.sleep(1)
if i%7 == 0:
pipe.send(5)
if __name__ == '__main__':
mainpipe,foopipe = multiprocessing.Pipe()
fooProcess = multiprocessing.Process(target=foo,name="Foo",args=(foopipe,))
fooProcess.start()
timer(10,mainpipe)
fooProcess.terminate()
# since we terminated, mainpipe and foopipe are corrupt
del mainpipe, foopipe
# ...
print 'Done'
I'm assuming that you want some condition in the foo process to extend the timer. In the sample I have set up, every time foo hits a multiple of 7 it extends the timer by 5 seconds while the timer initially counts down 10 seconds. At the end of the timer we terminate the process - foo won't finish nicely at all, and the pipes will get corrupted, but you can be certain that it'll die. Otherwise you can send a signal back along mainpipe that foo can listen for and exit nicely while you join.

Get time of execution of a block of code in Python 2.7

I would like to measure the time elapsed to evaluate a block of code in a Python program,
possibly separating between user cpu time, system cpu time and elapsed time.
I know the timeit module, but I have many self-written functions and it is not very easy
to pass them in the setup process.
I would rather have something that could be used like:
#up to here I have done something....
start_counting() #or whatever command used to mark that I want to measure
#the time elapsed in the next rows
# code I want to evaluate
user,system,elapsed = stop_counting() #or whatever command says:
#stop the timer and return the times
The user and system CPU times are not essential (though I would like to measure them),
but for the elapsed time I would like to be able to do something like this,
rather than using complicated commands or modules.
To get the elapsed time in seconds, you can use timeit.default_timer():
import timeit
start_time = timeit.default_timer()
# code you want to evaluate
elapsed = timeit.default_timer() - start_time
timeit.default_timer() is used instead of time.time() or time.clock() because it will choose the timing function that has the higher resolution for any platform.
I always use a decorator to do some extra work for a existing function, including to get the execution time. It is pythonic and simple.
import time
def time_usage(func):
def wrapper(*args, **kwargs):
beg_ts = time.time()
retval = func(*args, **kwargs)
end_ts = time.time()
print("elapsed time: %f" % (end_ts - beg_ts))
return retval
return wrapper
#time_usage
def test():
for i in xrange(0, 10000):
pass
if __name__ == "__main__":
test()
I found myself solving this problem again and again, so I finally created a library for it. Install with pip install timer_cm. Then:
from time import sleep
from timer_cm import Timer
with Timer('Long task') as timer:
with timer.child('First step'):
sleep(1)
for _ in range(5):
with timer.child('Baby steps'):
sleep(.5)
Output:
Long task: 3.520s
Baby steps: 2.518s (71%)
First step: 1.001s (28%)
You can achieve this through the Context Manager, for example:
from contextlib import contextmanager
import time
import logging
#contextmanager
def _log_time_usage(prefix=""):
'''log the time usage in a code block
prefix: the prefix text to show
'''
start = time.time()
try:
yield
finally:
end = time.time()
elapsed_seconds = float("%.2f" % (end - start))
logging.debug('%s: elapsed seconds: %s', prefix, elapsed_seconds)
use example:
with _log_time_usage("sleep 1: "):
time.sleep(1)
There is one more option which i loves a lot now for simplicity - ipython. In ipython you got a lot of useful stuff plus:
%time <expression> - to get straight cpu and wall time on expression
%timeit <expression> - to get cpu and wall time in a loop of expression
Python 3 - Simple solution using standard library
Option 1: Triple quote the code
import inspect
import timeit
code_block = inspect.cleandoc("""
base = 123456789
exponent = 100
return base ** exponent
""")
print(f'\Code block: {timeit.timeit(code_block, number=1, globals=globals())} elapsed seconds')
inspect.cleandoc handles the removal of extra tabs and whitespace so that blocks of code can be copied and pasted without getting indentation errors.
 
Option 2: Place code block in a function
import timeit
def my_function():
base = 123456789
exponent = 100
return base ** exponent
if __name__ == '__main__':
print(f'With lambda wrapper: {timeit.timeit(lambda: my_function(), number=1)} elapsed seconds')
Note that a function call will add additional execution time versus timing the function body directly.

Categories

Resources