9
votes

Y a-t-il une raison d'utiliser malloc sur pymem_malloc?

Je lis je lis le Documentation pour la gestion de la mémoire dans Python C Extensions , et aussi loin que je peux dire, il ne semble pas vraiment y avoir beaucoup de raison d'utiliser malloc plutôt que pymem_malloc . Disons que je veux allouer un tableau qui ne doit pas être exposé au code source Python et sera stocké dans un objet qui sera recruté. Y a-t-il une raison d'utiliser masloc ?


0 commentaires

3 Réponses :


1
votes

De mon expérience Ecrire des fonctions MATLAB .MEX, je pense que le plus gros facteur déterminant de savoir si vous utilisez MALLOC ou non est la portabilité. Dites que vous avez un fichier d'en-tête qui effectue une charge d'une charge utile à l'aide des types de données C internes uniquement (aucune interaction de l'objet Python nécessaire, donc aucun problème à l'aide de MALLOC), et vous vous rendez soudainement réalisez que vous souhaitez porter ce fichier d'en-tête sur une base de code différente qui a Rien à voir avec Python Que soit (peut-être que c'est un projet écrit purement en C), à l'aide de MALLOC, serait évidemment une solution beaucoup plus portable.

Mais pour votre code qui est purement une extension Python, ma réaction initiale serait de s'attendre à ce que la fonction Native C soit plus rapide. Je n'ai aucune preuve pour atteindre cet objectif :)


4 commentaires

Vous avez raison de s'attendre à ce que la fonction C Native C est meilleure. La chose est qu'ils sont tous deux natifs c fonctions. :-)


Eh bien, je suppose qu'ils sont ... Belle technicité :) Je suppose que je voulais dire plus que je m'attendais à ce que le système d'allocation de la mémoire native de C soit plus rapide que l'autochtone C implémenté pour le système d'allocation de mémoire de Python: P


J'ai utilisé Malloc et Pymem_Malloc. Mes points de repère ont montré une différence de performance négligible entre les deux. Pymem_Malloc peut avoir été plus rapide mais je ne pense pas que la différence était de manière statistique. YMMV, bien sûr.


De mon expérience dans Matlab, vous devez utiliser mxmalloc si possible ou n'oubliez pas de rétrograder sur toute erreur



7
votes

Il est parfaitement correct pour les extensions pour allouer la mémoire avec MALLOC ou d'autres allocateurs système. C'est normal et inévitable pour de nombreux types de modules - la plupart des modules qui enveloppent d'autres bibliothèques, ce qui ne savent rien sur Python, provoquera des allocations indigènes quand elles se produisent dans cette bibliothèque. (Certaines bibliothèques vous permettent de contrôler suffisamment l'affectation pour éviter cela; la plupart ne le font pas.)

Il y a un inconvénient grave à l'utilisation de pymem_malloc: vous devez tenir la gil à l'utiliser. Les bibliothèques indigènes souhaitent souvent libérer le gil lors de calculs à forte intensité de la CPU ou en faisant des appels pouvant bloquer, comme des E / S. Besoin de verrouiller le gil avant que les allocations puissent être quelque part entre très gênant et un problème de performance.

Utiliser les wrappers de Python pour une allocation de mémoire permet d'utiliser le code de débogage de la mémoire de Python. Avec des outils comme Valgrind, je doute de la valeur réelle de cela, cependant.

Vous devrez utiliser ces fonctions si une API l'exige; Par exemple, si une API est passée un pointeur qui doit être attribué à ces fonctions, il peut donc être libéré avec eux. En empêchant une raison explicite comme celle-là pour les utiliser, je m'enlève d'une allocation normale.


0 commentaires

8
votes

edit strong>: mixte pymem_malloc code> et pyObject_malloc code> corrections; ils sont deux appels différents.

sans le pymalloc_debug code> macro activé, pymem_malloc code> est un alias de MALLOC () code>, ayant un cas particulier : appeler pymem_malloc code> Pour allouer que zéro Byte retournera un pointeur non nulle, tandis que Malloc (zero_bytes) pourrait renvoyer une valeur nulle ou élever une erreur système ( Référence de code source ): P>

/ * malloc. Notez que nbytes == 0 essaie Pour retourner un pointeur non nul, distinct p>

  • de tous les autres points actuellement en direct. Cela peut ne pas être possible. * / li> ul> blockQuote>

    En outre, il existe une note de conseil sur le pymem.h code> fichier d'en-tête : p>

    Ne jamais mélanger les appels vers pymem_ avec Appels vers la plate-forme Malloc / Realloc / calloc / gratuitement. Par exemple, sous Windows Différentes dlls peuvent finir par utiliser différents tas, et si vous utilisez Pymem_malloc vous obtiendrez la mémoire du tas utilisé par le python Dll; Cela pourrait être une catastrophe si vous libre () 'ed qui directement dans votre propre extension. En utilisant pympem_free à la place assure que Python peut retourner la mémoire au bon tas. Comme un autre Exemple, en mode pymalloc_debug, Python enveloppe tous les appels vers tous pymem_ et pyObject_ la mémoire fonctionne dans emballages de débogage spéciaux qui ajoutent informations de débogage supplémentaires à Blocs de mémoire dynamique. Le système Les routines n'ont aucune idée de quoi faire avec ce genre de choses et le python Les wrappers n'ont aucune idée de quoi faire avec des blocs bruts obtenus directement par les routines du système alors. P> blockquote>

    Ensuite, il existe des réglages spécifiques à Python à l'intérieur pymem_malloc CODE> Strike> pyObject_malloc code>, une fonction utilisée non seulement pour les extensions C mais pour Toutes les allocations dynamiques lors de l'exécution d'un programme Python, comme 100 * 234 code>, str (100) code> ou 10 + 4j code>: p> xxx pré>

    Le complexe précédent () code> Les instances sont de petits objets alloués sur un pool dédié. p>

    petits objets ( pymem_malloc code> grève> pyobject_malloc code> est assez efficace car il est fait à partir d'une piscine 8 octets bloqués, un pool existant pour chaque taille de bloc. Il existe également des pages et des blocs Arenas pour des allocations plus grandes. P>

    Ce commentaire sur le code source explique comment l'appel pyObject_malloc code> est optimisé: p>

    /*
     * The basic blocks are ordered by decreasing execution frequency,
     * which minimizes the number of jumps in the most common cases,
     * improves branching prediction and instruction scheduling (small
     * block allocations typically result in a couple of instructions).
     * Unless the optimizer reorders everything, being too smart...
     */
    


3 commentaires

Les allocateurs indigènes sont déjà extrêmement optimisés. Cela n'a aucune incidence sur les modules d'extension - si quelque chose, ce n'est que des frais généraux supplémentaires pour ralentir les choses.


@Glenn Avez-vous des chiffres difficiles à soutenir cela? Les documents sont assez vastes et détaillés pour être juste un "frais de tête pour ralentir".


J'ai de l'expérience et du bon sens: l'allocator système affecte la vitesse de l'ensemble du système, de sorte que beaucoup d'efforts vont les optimiser. Si vous prétendez que Python s'améliore à ce sujet - pour une utilisation du module d'extension, non seulement le cas particulier du noyau de python de bas niveau - c'est votre prétention de sauvegarder.