Track CPU and memory usage of a python function [duplicate] - python

Hey I'm learning psutil package and I want to know how to display current CPU usage when function is in progress? I suppose I need some threading or something like this, but how to do it? Thank u for any answers.
import psutil
import random
def iHateThis():
tab = []
for i in range(100000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab;
while(True):
currentProcess = psutil.Process()
print(currentProcess.cpu_percent(interval=1))

You can use threading to run iHateThis or to run function with cpu_percent(). I choose second version. I will run cpu_percent() in thread.
Because it uses while True so thread would run forever and there wouldn't be nice method to stop thread so I use global variaable running with while running to have method to stop this loop.
import threading
import psutil
def display_cpu():
global running
running = True
currentProcess = psutil.Process()
# start loop
while running:
print(currentProcess.cpu_percent(interval=1))
def start():
global t
# create thread and start it
t = threading.Thread(target=display_cpu)
t.start()
def stop():
global running
global t
# use `running` to stop loop in thread so thread will end
running = False
# wait for thread's end
t.join()
and now I can use it to start and stop thread which will display CPU. Because I may have to stop process using Ctrl+C so it will raise error so I use try/finally to stop thread even if there will be error.
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
start()
try:
result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
stop()
Full code:
import random
import threading
import psutil
def display_cpu():
global running
running = True
currentProcess = psutil.Process()
# start loop
while running:
print(currentProcess.cpu_percent(interval=1))
def start():
global t
# create thread and start it
t = threading.Thread(target=display_cpu)
t.start()
def stop():
global running
global t
# use `running` to stop loop in thread so thread will end
running = False
# wait for thread's end
t.join()
# ---
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
start()
try:
result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
stop()
BTW: this can be converted to class which inherits from class Thread and then it can hide variable running in class.
import psutil
import random
import threading
class DisplayCPU(threading.Thread):
def run(self):
self.running = True
currentProcess = psutil.Process()
while self.running:
print(currentProcess.cpu_percent(interval=1))
def stop(self):
self.running = False
# ----
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
display_cpu = DisplayCPU()
display_cpu.start()
try:
result = i_hate_this()
finally: # stop thread even when I press Ctrl+C
display_cpu.stop()
It could be also converted to context manager to run it as
with display_cpu():
i_hate_this()
but I skip this part.

You can do this with the multiprocessing library. multiprocessing.Process is a class that represents a threaded process, is initiated with a function and name, and can be run at any time with .start().
import multiprocessing
import psutil
import random
def iHateThis():
tab = []
for i in range(100000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab;
hate = multiprocessing.Process(name='hate', target=iHateThis)
hate.start()
while(True):
currentProcess = psutil.Process()
print(currentProcess.cpu_percent(interval=1))

I don't think you need to use psutil Process class as I think it is intended to be used to monitor a specific process. Using the code snippet from #furas (the accepted answer), you can do it with a thread like this:
def run(self):
self.run = True
while self.run:
psutil.cpu_percent(interval=1)
it works the same as the accepted answer in the following case:
_monitor.start()
try:
for i in range(50):
time.sleep(0.2)
finally:
_monitor.stop()
If you don't want to code it, I am doing it in a public repo if it can be of any help for someone: https://github.com/GTimothee/monitor

Let approach the problem differently and propose a decorator that can serve to measure CPU utilization while running
from functools import partial, wraps
def log_cpu_usage(func=None, msg_prefix: str = None):
"""
This function is a decorator that measures the execution time of a function and logs it.
"""
debug = True
if not debug:
return func
if func is None:
return partial(log_cpu_usage, msg_prefix=msg_prefix)
def new_func(data: mp.Queue, *args, **kwargs):
result = func(*args, **kwargs)
data.put(result)
#wraps(func)
def trace_execution(*args, **kwargs):
manager = mp.Queue() # to save return val between multi process
worker_process = mp.Process(target=new_func, args=(manager, *args), kwargs=kwargs)
worker_process.start()
p = psutil.Process(worker_process.pid)
cpu_percents = []
while worker_process.is_alive(): # while the subprocess is running
cpu_percents.append(p.cpu_percent() / psutil.cpu_count())
time.sleep(0.01)
worker_process.join()
ret_values = manager.get()
return sum(cpu_percents) / len(cpu_percents), ret_values
#log_cpu_usage
def iHateThis():
pass

Related

How to wait for one threading to finish then run another threading

I need to open multiple chrome drivers with selenium, then execute my script by threading in them.
How to make it wait until first threading is finished and then start second threading.
time.sleep(x) wont work for me, as I do not know how much time would first threading take and I need second threading to start as soon as first one is finished.
import time
import threading
from selenium import webdriver
mydrivers=[]
tabs = []
class ActivePool(object):
def __init__(self):
super(ActivePool, self).__init__()
self.active = []
self.lock = threading.Lock()
def makeActive(self, name):
with self.lock:
self.active.append(name)
def makeInactive(self, name):
with self.lock:
self.active.remove(name)
def main_worker(s):
#Driver State
global tabs
global mydrivers
mydrivers.append(webdriver.Chrome())
tabs.append(False)
def worker(s, pool):
with s:
global tabs
global mydrivers
name = threading.currentThread().getName()
pool.makeActive(name)
x = tabs.index(False)
tabs[x] = True
mydrivers[x].get("https://stackoverflow.com")
time.sleep(15)
pool.makeInactive(name)
tabs[x]= False
for k in range(5):
t = threading.Thread(target=main_worker, args=(k,))
t.start()
# How to make it wait until above threading is finished and then start below threading
pool = ActivePool()
s = threading.Semaphore(5)
for j in range(100):
t = threading.Thread(target=worker, name=j, args=(s, pool))
t.start()
thds = []
for k in range(5):
thds.append( threading.Thread(target=main_worker, args=(k,)))
for t in thds:
t.start()
for t in thds:
t.join()
Or, even:
thds = [threading.Thread(target=main_worker, args=(k,)) for k in range(5)]
for t in thds:
t.start()
for t in thds:
t.join()
To wait for a thread to finish you should use the thread.join function. Eg...
from threading import Thread
import time
def wait_sec():
time.sleep(2)
my_thread = Thread(target=wait_sec)
my_thread.start()
# after starting the thread join it to wait for end of target
my_thread.join()
print("You have waited 2 seconds")

What is the best practice of 'restarting' a thread? [duplicate]

How can I start and stop a thread with my poor thread class?
It is in loop, and I want to restart it again at the beginning of the code. How can I do start-stop-restart-stop-restart?
My class:
import threading
class Concur(threading.Thread):
def __init__(self):
self.stopped = False
threading.Thread.__init__(self)
def run(self):
i = 0
while not self.stopped:
time.sleep(1)
i = i + 1
In the main code, I want:
inst = Concur()
while conditon:
inst.start()
# After some operation
inst.stop()
# Some other operation
You can't actually stop and then restart a thread since you can't call its start() method again after its run() method has terminated. However you can make one pause and then later resume its execution by using a threading.Condition variable to avoid concurrency problems when checking or changing its running state.
threading.Condition objects have an associated threading.Lock object and methods to wait for it to be released and will notify any waiting threads when that occurs. Here's an example derived from the code in your question which shows this being done. In the example code I've made the Condition variable a part of Thread subclass instances to better encapsulate the implementation and avoid needing to introduce additional global variables:
from __future__ import print_function
import threading
import time
class Concur(threading.Thread):
def __init__(self):
super(Concur, self).__init__()
self.iterations = 0
self.daemon = True # Allow main to exit even if still running.
self.paused = True # Start out paused.
self.state = threading.Condition()
def run(self):
self.resume()
while True:
with self.state:
if self.paused:
self.state.wait() # Block execution until notified.
# Do stuff...
time.sleep(.1)
self.iterations += 1
def pause(self):
with self.state:
self.paused = True # Block self.
def resume(self):
with self.state:
self.paused = False
self.state.notify() # Unblock self if waiting.
class Stopwatch(object):
""" Simple class to measure elapsed times. """
def start(self):
""" Establish reference point for elapsed time measurements. """
self.start_time = time.time()
return self
#property
def elapsed_time(self):
""" Seconds since started. """
try:
return time.time() - self.start_time
except AttributeError: # Wasn't explicitly started.
self.start_time = time.time()
return 0
MAX_RUN_TIME = 5 # Seconds.
concur = Concur()
stopwatch = Stopwatch()
print('Running for {} seconds...'.format(MAX_RUN_TIME))
concur.start()
while stopwatch.elapsed_time < MAX_RUN_TIME:
concur.resume()
# Can also do other concurrent operations here...
concur.pause()
# Do some other stuff...
# Show Concur thread executed.
print('concur.iterations: {}'.format(concur.iterations))
This is David Heffernan's idea fleshed-out. The example below runs for 1 second, then stops for 1 second, then runs for 1 second, and so on.
import time
import threading
import datetime as DT
import logging
logger = logging.getLogger(__name__)
def worker(cond):
i = 0
while True:
with cond:
cond.wait()
logger.info(i)
time.sleep(0.01)
i += 1
logging.basicConfig(level=logging.DEBUG,
format='[%(asctime)s %(threadName)s] %(message)s',
datefmt='%H:%M:%S')
cond = threading.Condition()
t = threading.Thread(target=worker, args=(cond, ))
t.daemon = True
t.start()
start = DT.datetime.now()
while True:
now = DT.datetime.now()
if (now-start).total_seconds() > 60: break
if now.second % 2:
with cond:
cond.notify()
The implementation of stop() would look like this:
def stop(self):
self.stopped = True
If you want to restart, then you can just create a new instance and start that.
while conditon:
inst = Concur()
inst.start()
#after some operation
inst.stop()
#some other operation
The documentation for Thread makes it clear that the start() method can only be called once for each instance of the class.
If you want to pause and resume a thread, then you'll need to use a condition variable.

How to monitor usage of CPU when function is called in Python psutil?

Hey I'm learning psutil package and I want to know how to display current CPU usage when function is in progress? I suppose I need some threading or something like this, but how to do it? Thank u for any answers.
import psutil
import random
def iHateThis():
tab = []
for i in range(100000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab;
while(True):
currentProcess = psutil.Process()
print(currentProcess.cpu_percent(interval=1))
You can use threading to run iHateThis or to run function with cpu_percent(). I choose second version. I will run cpu_percent() in thread.
Because it uses while True so thread would run forever and there wouldn't be nice method to stop thread so I use global variaable running with while running to have method to stop this loop.
import threading
import psutil
def display_cpu():
global running
running = True
currentProcess = psutil.Process()
# start loop
while running:
print(currentProcess.cpu_percent(interval=1))
def start():
global t
# create thread and start it
t = threading.Thread(target=display_cpu)
t.start()
def stop():
global running
global t
# use `running` to stop loop in thread so thread will end
running = False
# wait for thread's end
t.join()
and now I can use it to start and stop thread which will display CPU. Because I may have to stop process using Ctrl+C so it will raise error so I use try/finally to stop thread even if there will be error.
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
start()
try:
result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
stop()
Full code:
import random
import threading
import psutil
def display_cpu():
global running
running = True
currentProcess = psutil.Process()
# start loop
while running:
print(currentProcess.cpu_percent(interval=1))
def start():
global t
# create thread and start it
t = threading.Thread(target=display_cpu)
t.start()
def stop():
global running
global t
# use `running` to stop loop in thread so thread will end
running = False
# wait for thread's end
t.join()
# ---
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
start()
try:
result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
stop()
BTW: this can be converted to class which inherits from class Thread and then it can hide variable running in class.
import psutil
import random
import threading
class DisplayCPU(threading.Thread):
def run(self):
self.running = True
currentProcess = psutil.Process()
while self.running:
print(currentProcess.cpu_percent(interval=1))
def stop(self):
self.running = False
# ----
def i_hate_this():
tab = []
for i in range(1000000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab
# ---
display_cpu = DisplayCPU()
display_cpu.start()
try:
result = i_hate_this()
finally: # stop thread even when I press Ctrl+C
display_cpu.stop()
It could be also converted to context manager to run it as
with display_cpu():
i_hate_this()
but I skip this part.
You can do this with the multiprocessing library. multiprocessing.Process is a class that represents a threaded process, is initiated with a function and name, and can be run at any time with .start().
import multiprocessing
import psutil
import random
def iHateThis():
tab = []
for i in range(100000):
tab.append(random.randint(1, 10000))
tab.sort()
return tab;
hate = multiprocessing.Process(name='hate', target=iHateThis)
hate.start()
while(True):
currentProcess = psutil.Process()
print(currentProcess.cpu_percent(interval=1))
I don't think you need to use psutil Process class as I think it is intended to be used to monitor a specific process. Using the code snippet from #furas (the accepted answer), you can do it with a thread like this:
def run(self):
self.run = True
while self.run:
psutil.cpu_percent(interval=1)
it works the same as the accepted answer in the following case:
_monitor.start()
try:
for i in range(50):
time.sleep(0.2)
finally:
_monitor.stop()
If you don't want to code it, I am doing it in a public repo if it can be of any help for someone: https://github.com/GTimothee/monitor
Let approach the problem differently and propose a decorator that can serve to measure CPU utilization while running
from functools import partial, wraps
def log_cpu_usage(func=None, msg_prefix: str = None):
"""
This function is a decorator that measures the execution time of a function and logs it.
"""
debug = True
if not debug:
return func
if func is None:
return partial(log_cpu_usage, msg_prefix=msg_prefix)
def new_func(data: mp.Queue, *args, **kwargs):
result = func(*args, **kwargs)
data.put(result)
#wraps(func)
def trace_execution(*args, **kwargs):
manager = mp.Queue() # to save return val between multi process
worker_process = mp.Process(target=new_func, args=(manager, *args), kwargs=kwargs)
worker_process.start()
p = psutil.Process(worker_process.pid)
cpu_percents = []
while worker_process.is_alive(): # while the subprocess is running
cpu_percents.append(p.cpu_percent() / psutil.cpu_count())
time.sleep(0.01)
worker_process.join()
ret_values = manager.get()
return sum(cpu_percents) / len(cpu_percents), ret_values
#log_cpu_usage
def iHateThis():
pass

How to use a thread pool to do infinite loop function?

I want to do a infinite loop function.
Here is my code
def do_request():
# my code here
print(result)
while True:
do_request()
When use while True to do this, it's a little slow, so I want to use a thread pool to concurrently execute the function do_request(). How to do this ?
Just like use ab (Apache Bench) to test HTTP server.
Finally, I've solved this problem. I use a variable to limit the thread number.
Here is my final code, solved my problem.
import threading
import time
thread_num = 0
lock = threading.Lock()
def do_request():
global thread_num
# -------------
# my code here
# -------------
with lock:
thread_num -= 1
while True:
if thread_num <= 50:
with lock:
thread_num += 1
t = threading.Thread(target=do_request)
t.start()
else:
time.sleep(0.01)
Thanks for all replies.
You can use threading in Python to implement this.
Can be something similar to this (when using two extra threads only):
import threading
# define threads
task1 = threading.Thread(target = do_request)
task2 = threading.Thread(target = do_request)
# start both threads
task1.start()
task2.start()
# wait for threads to complete
task1.join()
task2.join()
Basically, you start as many threads as you need (make sure you don't get too many, so your system can handle it), then you .join() them to wait for tasks to complete.
Or you can get fancier with multiprocessing Python module.
Try the following code:
import multiprocessing as mp
import time
def do_request():
while(True):
print('I\'m making requests')
time.sleep(0.5)
p = mp.Process(target=do_request)
p.start()
for ii in range(10):
print 'I\'m also doing other things though'
time.sleep(0.7)
print 'Now it is time to kill the service thread'
p.terminate()
The main thread stars a service thread that does the request and goes on until it has to, and then it finishes up the service thread.
Maybe you can use the concurrent.futures.ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor
import time
def wait_on_b(hello):
time.sleep(1)
print(hello) # b will never complete because it is waiting on a.
return 5
def wait_on_a():
time.sleep(1)
print(a.result()) # a will never complete because it is waiting on b.
return 6
executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b, 3)
b = executor.submit(wait_on_a)
How about this?
from threading import Thread, Event
class WorkerThread(Thread):
def __init__(self, logger, func):
Thread.__init__(self)
self.stop_event = Event()
self.logger = logger
self.func = func
def run(self):
self.logger("Going to start the infinite loop...")
#Your code
self.func()
concur_task = WorkerThread(logger, func = do_request)
concur_task.start()
To end this thread...
concur_task.stop_event.set()
concur_task.join(10) #or any value you like

How to start and stop a thread

How can I start and stop a thread with my poor thread class?
It is in loop, and I want to restart it again at the beginning of the code. How can I do start-stop-restart-stop-restart?
My class:
import threading
class Concur(threading.Thread):
def __init__(self):
self.stopped = False
threading.Thread.__init__(self)
def run(self):
i = 0
while not self.stopped:
time.sleep(1)
i = i + 1
In the main code, I want:
inst = Concur()
while conditon:
inst.start()
# After some operation
inst.stop()
# Some other operation
You can't actually stop and then restart a thread since you can't call its start() method again after its run() method has terminated. However you can make one pause and then later resume its execution by using a threading.Condition variable to avoid concurrency problems when checking or changing its running state.
threading.Condition objects have an associated threading.Lock object and methods to wait for it to be released and will notify any waiting threads when that occurs. Here's an example derived from the code in your question which shows this being done. In the example code I've made the Condition variable a part of Thread subclass instances to better encapsulate the implementation and avoid needing to introduce additional global variables:
from __future__ import print_function
import threading
import time
class Concur(threading.Thread):
def __init__(self):
super(Concur, self).__init__()
self.iterations = 0
self.daemon = True # Allow main to exit even if still running.
self.paused = True # Start out paused.
self.state = threading.Condition()
def run(self):
self.resume()
while True:
with self.state:
if self.paused:
self.state.wait() # Block execution until notified.
# Do stuff...
time.sleep(.1)
self.iterations += 1
def pause(self):
with self.state:
self.paused = True # Block self.
def resume(self):
with self.state:
self.paused = False
self.state.notify() # Unblock self if waiting.
class Stopwatch(object):
""" Simple class to measure elapsed times. """
def start(self):
""" Establish reference point for elapsed time measurements. """
self.start_time = time.time()
return self
#property
def elapsed_time(self):
""" Seconds since started. """
try:
return time.time() - self.start_time
except AttributeError: # Wasn't explicitly started.
self.start_time = time.time()
return 0
MAX_RUN_TIME = 5 # Seconds.
concur = Concur()
stopwatch = Stopwatch()
print('Running for {} seconds...'.format(MAX_RUN_TIME))
concur.start()
while stopwatch.elapsed_time < MAX_RUN_TIME:
concur.resume()
# Can also do other concurrent operations here...
concur.pause()
# Do some other stuff...
# Show Concur thread executed.
print('concur.iterations: {}'.format(concur.iterations))
This is David Heffernan's idea fleshed-out. The example below runs for 1 second, then stops for 1 second, then runs for 1 second, and so on.
import time
import threading
import datetime as DT
import logging
logger = logging.getLogger(__name__)
def worker(cond):
i = 0
while True:
with cond:
cond.wait()
logger.info(i)
time.sleep(0.01)
i += 1
logging.basicConfig(level=logging.DEBUG,
format='[%(asctime)s %(threadName)s] %(message)s',
datefmt='%H:%M:%S')
cond = threading.Condition()
t = threading.Thread(target=worker, args=(cond, ))
t.daemon = True
t.start()
start = DT.datetime.now()
while True:
now = DT.datetime.now()
if (now-start).total_seconds() > 60: break
if now.second % 2:
with cond:
cond.notify()
The implementation of stop() would look like this:
def stop(self):
self.stopped = True
If you want to restart, then you can just create a new instance and start that.
while conditon:
inst = Concur()
inst.start()
#after some operation
inst.stop()
#some other operation
The documentation for Thread makes it clear that the start() method can only be called once for each instance of the class.
If you want to pause and resume a thread, then you'll need to use a condition variable.

Categories

Resources