You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
Problem emerged in #1667 (comment), and it's a nasty one to solve in terms of API. The only idea I can think of right now which doesn't require using a class is passing a dict parameter as in:
If map is passed, the last/internal CPU timings should be stored in the dict and not in the global var. This same approach is used by the (now deprecated) asyncore stdlib module.
The same problem would also affect psutil.process_iter() if we introduce the new new_only parameter, which I reverted precisely for this reason (see #1667 (comment)). So theoretically if we decide to stick with this approach also process_iter() should get a map parameter (so 3 functions in total).
The text was updated successfully, but these errors were encountered:
`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:
```python
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
```
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):
Problem emerged in #1667 (comment), and it's a nasty one to solve in terms of API. The only idea I can think of right now which doesn't require using a class is passing a dict parameter as in:
If
map
is passed, the last/internal CPU timings should be stored in the dict and not in the global var. This same approach is used by the (now deprecated) asyncore stdlib module.The same problem would also affect
psutil.process_iter()
if we introduce the newnew_only
parameter, which I reverted precisely for this reason (see #1667 (comment)). So theoretically if we decide to stick with this approach alsoprocess_iter()
should get amap
parameter (so 3 functions in total).The text was updated successfully, but these errors were encountered: