globals: Fix a race condition in namedtuple_to_dict

namedtuple_to_dict() loops over a dynamic view of the dict of processes;
other threads might be editing the same dict.

For instance in webserver mode, when a race condition happens, the
following error shows up in the console:

>   File "C:\Users\ryabtsev\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glances\processes.py", line 628, in update_list
>     return list_of_namedtuple_to_list_of_dict(processlist)
>   File "C:\Users\ryabtsev\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glances\globals.py", line 495, in list_of_namedtuple_to_list_of_dict
>     return [namedtuple_to_dict(d) for d in data]
>             ^^^^^^^^^^^^^^^^^^^^^
>   File "/app/glances/globals.py", line 490, in namedtuple_to_dict
>     return {k: (v._asdict() if hasattr(v, '_asdict') else v) for k, v in data.items()}
>                                                                          ^^^^^^^^^^^^
> RuntimeError: dictionary changed size during iteration

Instead of a dict view, namedtuple_to_dict() will use a list of tuples.

Performances are unchanged: on average, for 100 runs, namedtuple_to_dict()
completes in 0.2ms

GH issue: #3097
Link: https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
This commit is contained in:
Ariel Otilibili 2025-05-27 14:27:41 +02:00 committed by nicolargo
parent 7c0dee3a63
commit 3488760ae5
1 changed files with 1 additions and 1 deletions

View File

@ -496,7 +496,7 @@ def weak_lru_cache(maxsize=128, typed=False):
def namedtuple_to_dict(data):
"""Convert a namedtuple to a dict, using the _asdict() method embedded in PsUtil stats."""
return {k: (v._asdict() if hasattr(v, '_asdict') else v) for k, v in data.items()}
return {k: (v._asdict() if hasattr(v, '_asdict') else v) for k, v in list(data.items())}
def list_of_namedtuple_to_list_of_dict(data):