Maison >développement back-end >Tutoriel Python >Valeurs mutables de mise en cache Python
La mise en cache accélère considérablement le traitement, des opérations au niveau du processeur aux interfaces de base de données. Invalidation du cache - déterminant quand supprimer les données mises en cache - est un défi complexe. Ce message aborde un problème de mise en cache plus simple, mais insidieux.
Ce problème, qui se cache pendant 18 mois, n'a fait surface que lorsque les utilisateurs se sont déviés du modèle d'utilisation recommandé. Le problème provenait d'un cadre d'apprentissage automatique personnalisé (ML) (construit sur Scikit-Learn) au sein de mon organisation. Ce cadre accède fréquemment à plusieurs sources de données, nécessitant une couche de mise en cache pour les performances et l'optimisation des coûts (réduction des coûts de sortie de BigQuery).Initialement,
a été utilisé, mais un cache persistant était nécessaire pour les données statiques fréquemment accessibles pendant le développement. lru_cache
, une bibliothèque Python utilisant SQLite, a été choisie pour sa simplicité et sa compatibilité avec notre environnement 32-processus et les Pandas DataFrames (jusqu'à 500 Mo). Une couche DiskCache
a été ajoutée en haut pour un accès en mémoire. lru_cache
Notre norme de codage a dicté la création de nouveaux dataframes après tout traitement. Cependant, certains utilisateurs, par habitude, ont utilisé
, modifiant directement l'objet mis en cache. Cela a non seulement modifié leurs résultats immédiats, mais a également corrompu les données mises en cache, affectant les demandes ultérieures. inplace=True
<code class="language-python">from functools import lru_cache import time import typing as t from copy import deepcopy @lru_cache def expensive_func(keys: str, vals: t.Any) -> dict: time.sleep(3) return dict(zip(keys, vals)) def main(): e1 = expensive_func(('a', 'b', 'c'), (1, 2, 3)) print(e1) e2 = expensive_func(('a', 'b', 'c'), (1, 2, 3)) print(e2) e2['d'] = "amazing" print(e2) e3 = expensive_func(('a', 'b', 'c'), (1, 2, 3)) print(e3) if __name__ == "__main__": main()</code>
fournit une référence, pas une copie. La modification lru_cache
modifie les données en cache. e2
Solution:
La solution consiste à renvoyer une copie profonde de l'objet mis en cache:
<code class="language-python">from functools import lru_cache, wraps from copy import deepcopy def custom_cache(func): cached_func = lru_cache(func) @wraps(func) def _wrapper(*args, **kwargs): return deepcopy(cached_func(*args, **kwargs)) return _wrapper</code>Cela ajoute une petite surcharge (duplication de données), mais empêche la corruption des données.
Prise des clés:
lru_cache
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!