Nous avons un serveur Web basé sur Python qui impasse un certain nombre de fichiers de données volumineux au démarrage à l'aide de Le goulot d'étranglement n'est certainement pas du disque (il faut moins de 0,5 à la lecture de nombreuses données), mais une allocation de mémoire et une création d'objets (des millions d'objets sont créés). Nous voulons réduire les 20s pour réduire le temps de démarrage. P>
Y a-t-il un moyen de désérialiser plus de 1 Go d'objets dans Python beaucoup plus rapidement que Je sais que certaines langues interprétées ont un moyen d'enregistrer leur image de mémoire entière en tant que fichier de disque, afin de pouvoir le charger dans la mémoire, tout en une seule fois, sans allocation / création pour chaque objet. Y a-t-il un moyen de faire cela ou d'atteindre quelque chose de similaire, à Python? P> CPICKLE code>. Les fichiers de données (mariné à l'aide de
le plus élevé_protocol >) sont autour de 0,4 Go sur disque et se chargent dans la mémoire comme environ 1,2 Go d'objets Python - cela prend environ
cpickle code> (comme 5-10x)? Étant donné que le temps d'exécution est lié par la répartition de la mémoire et la création d'objets, je présume en utilisant une autre technique de ponctuelle telle que JSON ne vous aiderait pas ici. P>
6 Réponses :
Je n'ai pas utilisé cpickle (ou python) mais dans des cas comme celui-ci, je pense que la meilleure stratégie est de Évitez de charger inutilement des objets jusqu'à ce qu'ils soient vraiment nécessaires - dites la charge après le démarrage sur un fil différent, il est généralement préférable d'éviter une chargement / initialisation inutile à tout moment pour des raisons évidentes. Google 'Chargement paresseux' ou «initialisation paresseux». Si vous avez vraiment besoin de tous les objets pour effectuer une tâche avant le démarrage du serveur, vous pouvez peut-être essayer d'implémenter une méthode de désérialisation personnalisée manuelle, dans d'autres termes, implémentez-vous vous-même si vous avez une connaissance intime des données que vous ferez gérer ce que vous pourrez vous aider. 'Squeeze' meilleure performance puis l'outil général pour traiter avec elle. p>
Avez-vous essayé de sacrifier l'efficacité du décapage en utilisant le plus haut_protocol? Il n'est pas clair que les coûts de performance sont associés à l'utilisation de ce protocole, mais cela vaut la peine d'essayer. P>
Bonne pensée. Cependant, nous utilisions le protocole par défaut (le plus bas) au début, mais le basculement de la plus haute_protocole (un protocole basé sur un binaire) a augmenté d'un facteur de deux. Donc, la plus haute_protocol est définitivement plus rapide.
impossible de répondre à cela sans en savoir plus sur le type de données que vous chargez et comment vous l'utilisez. P>
S'il s'agit d'une sorte de logique commerciale, vous devriez peut-être essayer de le transformer en un module pré-compilé; p>
S'il s'agit de données structurées, pouvez-vous le déléguer à une base de données et tirer uniquement la traction de ce qui est nécessaire? P>
Les données ont-elles une structure régulière? Y a-t-il un moyen de diviser et de décider de ce qui est requis et ne le charge que? P>
Êtes-vous chargée () les données marinées directement dans le fichier? Qu'essaie de charger le fichier dans la mémoire et de faire la charge? Je commencerais avec essayer le cstringio (); Sinon, vous pouvez essayer d'écrire votre propre version de StringIO qui utiliserait la mémoire tampon () pour trancher la mémoire qui réduirait les opérations de copie indispensable () (Cstringio peut toujours être plus rapide, mais vous devrez essayer). P>
Il existe parfois d'énormes goulots d'étranglement performants lors de ce type d'opérations, en particulier sur la plate-forme Windows; Le système Windows est en quelque sorte très désopatisé pour faire beaucoup de petites lectures alors que les UNIXES code assez bien; Si la charge (), beaucoup de petites lectures ou que vous appelez à plusieurs reprises pour lire les données, cela vous aiderait. P>
À la personne qui m'a donné le -1: essayez de charger un fichier en appelant Lire (1) sur la victoire; Ensuite, essayez de le faire sur UNIX. Il faut plusieurs secondes pour lire quelques mégaoctets sous Windows; Il est toujours instantané sur UNIX. Si Benhoyt charge beaucoup d'objets en appelant plusieurs dizaines de milliers de pickle.load () d'un fichier, cela pourrait être un facteur.
Bon appel. Sur nos données, changer "obj = pickle.load (f)" sur "S = F.Read (); obj = pickle.loads (s)" donne une augmentation de vitesse de 30%. Pas les ordres de grandeur, mais la peine d'être connue. (BTW, je me suis accidentellement enfoncé au lieu de monter; N'hésitez pas à modifier mineur à votre réponse afin que je puisse la faire uppoter.)
J'ai trouvé qu'il y a une amélioration assez substantielle pour faire le même processus avec le module maréchal (ce qui a du sens puisqu'il s'agit d'un problème de Windows).
Essayez le module maréchal - il est interne (utilisé par le byte-compilateur) et intentionnellement non annoncé beaucoup, mais c'est beaucoup plus rapide. Notez qu'il ne sérialiste pas les instances arbitraires telles que le cornichon, seuls des types intégrés (ne me souviennent pas des contraintes exactes, voir Docs). Notez également que le format n'est pas stable. P> li>
Si vous devez initialiser plusieurs processus et que vous pouvez tolérer un processus toujours chargé, il existe une solution élégante: chargez les objets dans un processus, puis ne le faites rien, à l'exception des processus de forcement à la demande. Forking est rapide (copier sur l'écriture) et partage la mémoire entre tous les processus. [Disclaçabilités: non testée; Contrairement à Ruby , Python Ref Comptage déclenchera des copies de la page afin que cela soit probablement inutile si vous avez énormes em> objets et / ou accédez à une petite fraction d'entre eux.] P> LI>
Si vos objets contiennent beaucoup de données brutes telles que des tableaux numpoptés, vous pouvez les mémoriser la mémoire pour une démarrage beaucoup plus rapide. Pytables est également bon pour ces scénarios. P> Li>
Si vous n'utilisez qu'une petite partie des objets, une base de données OO (comme Zope's) peut probablement vous aider. Bien que si vous en avez besoin de la mémoire, vous ne perdrez que beaucoup de frais généraux. (jamais utilisé un, donc cela pourrait être absurde). P> li>
Peut-être que d'autres implémentations de Python peuvent le faire? Je ne sais pas, juste une pensée ... p> li>
ol>
Merci, des trucs utiles. FYI, dans mon test rapide sur un grand fichier avec de nombreux objets, Marshal.loads () était environ deux fois plus vite que Pickle.loads ().
Même expérience ici sur un énorme dictionnaire; Marshal.Load ne prend que 0,78s, où cpickle.load prend 1.2S.
L'option numéro deux serait problématique, car les objets seront copiés pour chaque sous-processus préféré au moment où vous faites référence à ces objets. En effet, chaque objet a un compte de référence qui change chaque fois que vous accédez à l'objet. Cela est à son tour comme changer l'objet et provoque ainsi la copie de la mémoire. Copie essentiellement sur l'écriture devient copie sur l'accès lorsque Python est concerné ...
@ Anti666: En effet, cependant, pour des objets "larges" - énormes listes ou dict-dicts - la majeure partie de la mémoire reste sable, juste les en-têtes sont inclus / Decref'd. Si l'enfant va accéder à une grande partie des données, les défauts de la page coûteront beaucoup plus cher que l'enregistrement. En supposant que cela ne nécessite que de petites portions des données à la fois i>, les meilleures approches sont des éléments comme NUMPY / PYTABLES / OO DBS qui prennent en charge l'accès aléatoire mais matérialisent des objets Python à la demande. Heck, même étagère code> pourrait être bon! [Disclaimer: Je n'ai jamais chronométré comme ceci, spéculer simplement ...]
Je vais ajouter une autre réponse qui pourrait être utile - si vous le pouvez, pouvez-vous essayer de définir les emplacements _ em> _ sur la classe la plus couramment créée? Cela peut être un peu limitant et impossible, mais il semble avoir réduit le temps nécessaire à l'initialisation de mon test à environ demi. P>
Cela pourrait être votre chance d'obtenir un lecteur d'état solide. Est-ce pour accélérer le développement? Vous permettre de faire des déploiements rapides? Le décalage est-il en train de lire les données ou de le désactiver? Si vous commencez par un exemple vide, quel est le temps de démarrage?
Notez que je mentionne dans ma question que le goulot d'étranglement n'est pas de la vitesse de conduire / de lecture, mais de la rapidité de la création d'objet et de l'objet. C'est plus pour des déploiements rapides - pour permettre à notre serveur de redémarrer rapidement. Je ne suis pas tout à fait sûr de ce que vous entendez par "instance vide" ici.
Pour un fichier binaire de cornichon de 750 Mo, enveloppez l'appel de chargement CPickle avec GC.Disable () / GC.Enable () réduit considérablement le temps total requis par environ 20x. Voir ici