giampaolo / psutil

Cross-platform lib for process and system monitoring in Python
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.38k forks source link

psutil.cpu_percent() is not thread safe (fixes #1703) #2282

Closed giampaolo closed 1 year ago

giampaolo commented 1 year ago

Summary

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):

3.5
3.5
0.0
0.0

2.8
2.8
0.0
0.0

2.5
2.5
0.0
0.0

2.5
2.5
2.5
2.5

3.3
3.3
3.3
50.0

2.8
0.0
0.0
0.0

After patch:

0.0
0.0
0.0

0.0
2.0
2.3
2.3
2.3

5.5
5.3
5.5
5.5

3.3
3.3
3.0
3.0

9.0
8.9
9.0
9.4

30.0
30.0
29.6
30.0

24.7
24.7
24.7
24.7