Maison  >  Article  >  développement back-end  >  Dernier open source : bibliothèque de pooling d'objets universelle Python efficace

Dernier open source : bibliothèque de pooling d'objets universelle Python efficace

王林
王林avant
2023-04-17 09:04:021318parcourir

Dernier open source : bibliothèque de pooling d'objets universelle Python efficace

En programmation, la création de modules objets se fait principalement en générant des objets. Lorsque l'objet est utilisé, il deviendra un module qui n'est plus nécessaire et sera détruit.

Lorsque le système génère et détruit des objets, la consommation de mémoire sera considérablement augmentée. Dans le même temps, la destruction d'objets laisse souvent des informations résiduelles, ce qui s'accompagnera du problème des fuites de mémoire.

Dans le processus de développement du programme lui-même, il est souvent nécessaire de générer et de détruire un grand nombre d'objets en double. Cela rend les informations générées par les fuites de mémoire trop importantes et ne peuvent pas être recyclées par le système, occupant ainsi plus de mémoire du système. , et lorsque trop d'objets sont générés, il est impossible de déterminer quel module est instancié et implémenté, ce qui alourdit le système et n'est pas propice à la gestion et aux opérations ultérieures. À long terme, cela finira par ralentir le programme. tomber ou même s'écraser.

Le pool d'objets est un pool qui stocke un lot d'objets créés. C'est une structure utilisée pour maintenir les objets. Lorsque le programme a besoin d'utiliser un objet, il peut obtenir l'objet directement à partir du pool au lieu d'instancier un nouvel objet.

Dans le processus de programmation, la plupart des gens ont tendance à se concentrer uniquement sur l'utilisation des objets et la réalisation des effets. En fait, il existe un processus d'initialisation entre la création et l'utilisation, mais le système combinera les deux étapes d'initialisation et d'utilisation. création. Ensemble, cela amène le concepteur à ignorer l'impact du processus de création et de destruction d'objets du système sur le système.

De manière générale, le coût de création et de destruction d'un objet est très faible et peut être ignoré. Cependant, si un programme implique plusieurs créations d'un objet et que le temps de création est relativement long, la consommation de celui-ci sera évidente. une partie limite la vitesse du système.

Le pool d'objets peut être considéré comme la méthode préférée pour réduire la pression du GC, et c'est aussi la méthode la plus simple.

Le mode pool d'objets convient principalement aux scénarios d'application suivants :

  • Scénarios à ressources limitées. Par exemple, dans un environnement qui ne nécessite pas d'évolutivité (les ressources physiques telles que le processeur et la mémoire sont limitées), les performances du processeur ne sont pas assez fortes, la mémoire est relativement limitée, le garbage collection et la gigue de la mémoire auront un impact relativement important, et l'efficacité de la gestion de la mémoire doit être améliorée. La réactivité est meilleure que le débit est plus important.
  • Un nombre limité d'objets en mémoire.
  • Des objets qui coûtent cher à créer.
  • Un grand nombre d'objets à durée de vie courte et à faible coût d'initialisation sont regroupés pour réduire les coûts d'allocation et de réallocation de mémoire et éviter la fragmentation de la mémoire.
  • Dans un langage dynamique comme Python, GC s'appuie sur une technologie de référence pour garantir que les objets ne seront pas recyclés prématurément. Dans certains scénarios, il peut y avoir une période d'inactivité créée mais non utilisée, entraînant le recyclage de l'objet. Il peut être délégué au pool d’objets pour sa conservation.

Pond Introduction

Pond est un pool d'objets général efficace en Python, avec les caractéristiques de bonnes performances, une faible empreinte mémoire et un taux de réussite élevé. La possibilité de recycler automatiquement en fonction de la fréquence basée sur des statistiques approximatives permet d'ajuster automatiquement le nombre d'objets libres dans chaque pool d'objets.

Parce qu'actuellement Python ne dispose pas d'une meilleure bibliothèque de pooling d'objets avec des cas de test complets, des commentaires de code complets et une documentation complète. Dans le même temps, la bibliothèque de pooling d'objets grand public actuelle ne dispose pas d'un mécanisme de recyclage automatique intelligent.

Pond est peut-être la première bibliothèque de pooling d'objets en Python avec des cas de test complets divulgués par la communauté, un taux de couverture de plus de 90 %, des commentaires de code complets et une documentation complète.

Pond s'inspire d'Apache Commons Pool, Netty Recycler, HikariCP et Caffeine, intégrant les avantages de beaucoup d'entre eux.

Deuxièmement, Pond compte la fréquence d'utilisation de chaque pool d'objets dans un très petit espace mémoire en utilisant un comptage approximatif et le recycle automatiquement.

Lorsque le trafic est relativement aléatoire et moyen, la stratégie et le poids par défaut peuvent réduire l'utilisation de la mémoire de 48,85 % et le taux de réussite de l'emprunt est de 100 %.

Dernier open source : bibliothèque de pooling d'objets universelle Python efficace

Lorsque le trafic est plus conforme à la loi 2/8, la stratégie et le poids par défaut peuvent réduire l'utilisation de la mémoire de 45,7 % et le taux de réussite de l'emprunt est de 100 %.

Dernier open source : bibliothèque de pooling d'objets universelle Python efficace

Aperçu du design

Pond est principalement composé de FactoryDict, Counter, PooledObjectTree et d'un fil de recyclage séparé.

FactoryDict

L'utilisation de Pond nécessite l'implémentation de la fabrique d'objets PooledObjectFactory qui fournit la création, l'initialisation, la destruction, la vérification et d'autres opérations d'objets, et est appelée par Pond.

Ainsi, pour que le pool d'objets prenne en charge le stockage d'objets complètement différents, Pond utilise un dictionnaire pour enregistrer le nom de chaque classe d'usine et l'objet instancié de la classe d'usine qu'il implémente.

Chaque PooledObjectFactory doit avoir les quatre fonctions de création d'objets, de destruction d'objets, de vérification si les objets sont toujours disponibles et de réinitialisation des objets.

Ce qui est spécial, c'est que Pond prend en charge la réinitialisation automatique des objets, car dans certains scénarios, il peut y avoir des situations où l'objet doit d'abord se voir attribuer une valeur et être transmis, puis être recyclé après avoir été transmis afin d'éviter toute contamination. Il est recommandé d'implémenter cette fonction dans de tels scénarios.

Counter

Counter stocke un compteur approximatif.

PooledObjectTree

PooleedObjectTree est un dictionnaire, et chaque clé correspond à une file d'attente premier entré, premier sorti. Ces files d'attente sont thread-safe.

Chaque file d'attente contient plusieurs PooleedObjects. PooledObject enregistre l'heure de création, l'heure du dernier prêt et l'objet réellement requis.

Sécurité des fils

L'emprunt et le recyclage de Pond sont tous deux sans danger pour les fils. Le module de file d'attente de Python fournit une structure de données premier entré, premier sorti (FIFO) adaptée à la programmation multithread. Il peut être utilisé pour transmettre en toute sécurité des messages ou d’autres données entre les threads producteur et consommateur.

Le verrou est géré par l'appelant et tous les threads multiples peuvent fonctionner en toute sécurité et facilement en utilisant la même instance de file d'attente. L'emprunt et le recyclage de Pond fonctionnent tous deux sur la file d'attente, ils peuvent donc fondamentalement être considérés comme thread-safe.

Mécanisme de prêt

Lorsque vous utilisez Pond pour prêter un objet, il vérifiera d'abord si le type d'objet que vous souhaitez prêter existe déjà dans PooledObjectTree. S'il existe, il vérifiera si le pool d'objets de cet objet est vide. Si tel est le cas, Empty en créera un nouveau.

S'il y a des objets en excès dans le pool d'objets, la file d'attente sera utilisée pour faire apparaître un objet et vérifier si cet objet est disponible. S'il n'est pas disponible, la Factory correspondante sera automatiquement appelée pour nettoyer et détruire l'objet. En même temps, son compte GC en Python sera effacé, afin qu'il puisse être recyclé par GC plus rapidement, et le suivant sera pris. en continu jusqu'à ce qu'il y en ait un disponible.

Si cet objet est disponible, il sera restitué directement. Bien entendu, qu'un objet soit retiré du pool d'objets ou qu'un nouvel objet soit créé, Counter sera utilisé pour incrémenter un décompte.

Mécanisme de recyclage

Lors du recyclage d'un objet, il déterminera si le pool d'objets cible existe. S'il existe, il vérifiera si le pool d'objets est plein. S'il est plein, l'objet à restituer le sera automatiquement. détruit.

Ensuite, il vérifiera si l'objet a été prêté trop longtemps. S'il dépasse la durée maximale configurée, il sera également effacé.

Recyclage automatique

Le recyclage automatique sera exécuté de temps en temps, la valeur par défaut est de 300 s. Nettoyez automatiquement les objets du pool d'objets qui ne sont pas fréquemment utilisés.

Instructions

Vous pouvez d'abord installer la bibliothèque Pond et la référencer dans votre projet.

pip install pondpond
from pond import Pond, PooledObjectFactory, PooledObject

Vous devez d'abord déclarer une classe d'usine pour le type d'objet que vous souhaitez insérer. Par exemple, dans l'exemple ci-dessous, nous voulons que l'objet regroupé soit Dog, nous déclarons donc d'abord une classe PooledDogFactory et implémentons PooledObjectFactory.

class Dog:
 name: str
 validate_result:bool = True
class PooledDogFactory(PooledObjectFactory):
 def creatInstantce(self) -> PooledObject:
 dog = Dog()
 dog.name = "puppy"
 return PooledObject(dog)
 def destroy(self, pooled_object: PooledObject):
 del pooled_object
 def reset(self, pooled_object: PooledObject) -> PooledObject:
 pooled_object.keeped_object.name = "puppy"
 return pooled_object
 def validate(self, pooled_object: PooledObject) -> bool:
 return pooled_object.keeped_object.validate_result

Ensuite, vous devez créer l'objet Pond :

pond = Pond(borrowed_timeout=2,
 time_between_eviction_runs=-1,
 thread_daemon=True,
 eviction_weight=0.8)

Pond peut transmettre certains paramètres, qui représentent :

borrowed_timeout : l'unité est la seconde, la période maximale de l'objet prêté, l'objet qui dépasse la période sera sera automatiquement détruit une fois retourné. Ne sera pas mis dans le pool d'objets.

time_between_eviction_runs : L'unité est la seconde, l'intervalle entre le recyclage automatique.

thread_daemon : thread démon, si True, le thread automatiquement recyclé sera fermé lorsque le thread principal sera fermé.

eviction_weight : Le poids lors du recyclage automatique. Ce poids sera multiplié par la fréquence d'utilisation maximale. Les objets du pool d'objets dont la fréquence d'utilisation est inférieure à cette valeur entreront dans l'étape de nettoyage.

Classe d'usine instanciée :

factory = PooledDogFactory(pooled_maxsize=10, least_one=False)

Tout ce qui hérite de PooledObjectFactory aura son propre constructeur qui peut transmettre les paramètres pooled_maxsize et least_one.

pooled_maxsize : Le nombre maximum d'objets pouvant être placés dans le pool d'objets généré par cette classe d'usine.

least_one : Si True, lors du nettoyage automatique, le pool d'objets générés par cette classe d'usine conservera au moins un objet.

Enregistrez cet objet d'usine auprès de Pond. Par défaut, le nom de classe de l'usine sera utilisé comme clé de PooledObjectTree :

pond.register(factory)

Bien sûr, vous pouvez également personnaliser son nom, et le nom sera utilisé comme nom. clé de PooledObjectTree :

pond.register(factory, name="PuppyFactory")

Après un enregistrement réussi, Pond commencera automatiquement à créer des objets en fonction de la taille pooled_maxsize définie en usine jusqu'à ce que le pool d'objets soit rempli.

Emprunter et rendre des objets :

pooled_object: PooledObject = pond.borrow(factory)
dog: Dog = pooled_object.use()
pond.recycle(pooled_object, factory)

Bien sûr, vous pouvez emprunter et rendre des objets par nom :

pooled_object: PooledObject = pond.borrow(name="PuppyFactory")
dog: Dog = pooled_object.use()
pond.recycle(pooled_object, name="PuppyFactory")

Effacer complètement un pool d'objets :

pond.clear(factory)

Effacer un pool d'objets par son nom :

pond.clear(name="PuppyFactory")

Normalement, vous seul Vous devez utiliser les méthodes ci-dessus, et la génération et le recyclage d'objets sont entièrement automatiques.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer