psutil.cpu_percent(interval=None) and psutil.cpu_times_percent(interval=None) are non-blocking functions returning the CPU percent consumption since the last time they were called. In order to do so they use a global variable, in which the last CPU timings are saved, and that means they are not thread safe. E.g., if 10 threads call cpu_percent(interval=None) with a 1 second interval, only 1 thread out of 10 will get the right result, as it will "invalidate" the timings for the other 9. Problem can be reproduced with the following script:
import threading, time, psutil
NUM_WORKERS = psutil.cpu_count()
def measure_cpu():
while 1:
print(psutil.cpu_percent())
time.sleep(1)
for x in range(NUM_WORKERS):
threading.Thread(target=measure_cpu).start()
while 1:
print()
time.sleep(1.1)
The output looks like this, and it shows how inconsistent CPU measurements are between different threads (notice 0.0 values):
Summary
Description
psutil.cpu_percent(interval=None)
andpsutil.cpu_times_percent(interval=None)
are non-blocking functions returning the CPU percent consumption since the last time they were called. In order to do so they use a global variable, in which the last CPU timings are saved, and that means they are not thread safe. E.g., if 10 threads callcpu_percent(interval=None)
with a 1 second interval, only 1 thread out of 10 will get the right result, as it will "invalidate" the timings for the other 9. Problem can be reproduced with the following script:The output looks like this, and it shows how inconsistent CPU measurements are between different threads (notice 0.0 values):
After patch: