web-dev-qa-db-fra.com

Comment supprimer un RDD dans PySpark dans le but de libérer des ressources?

Si j'ai un RDD dont je n'ai plus besoin, comment le supprimer de la mémoire? Les éléments suivants suffiraient-ils pour y parvenir:

del thisRDD

Merci!

21
Ego

Non, del thisRDD Ne suffit pas, cela supprimerait simplement le pointeur vers le RDD. Vous devez appeler thisRDD.unpersist() pour supprimer les données mises en cache.

Pour votre information, Spark utilise un modèle de calculs paresseux, ce qui signifie que lorsque vous exécutez ce code:

>>> thisRDD = sc.parallelize(xrange(10),2).cache()

vous n'aurez pas vraiment de données en cache, elles ne seront marquées que 'à mettre en cache' dans le plan d'exécution RDD. Vous pouvez le vérifier de cette façon:

>>> print thisRDD.toDebugString()
(2) PythonRDD[6] at RDD at PythonRDD.scala:43 [Memory Serialized 1x Replicated]
 |  ParallelCollectionRDD[5] at parallelize at PythonRDD.scala:364 [Memory Serialized 1x Replicated]

Mais lorsque vous appelez une action au-dessus de ce RDD au moins une fois, elle devenait mise en cache:

>>> thisRDD.count()
10
>>> print thisRDD.toDebugString()
(2) PythonRDD[6] at RDD at PythonRDD.scala:43 [Memory Serialized 1x Replicated]
 |       CachedPartitions: 2; MemorySize: 174.0 B; TachyonSize: 0.0 B; DiskSize: 0.0 B
 |  ParallelCollectionRDD[5] at parallelize at PythonRDD.scala:364 [Memory Serialized 1x Replicated]

Vous pouvez facilement vérifier les données persistantes et le niveau de persistance dans l'interface utilisateur Spark en utilisant l'adresse http://<driver_node>:4040/storage. Vous y verriez que del thisRDD Ne changera pas la persistance de ce RDD, mais thisRDD.unpersist() le dissiperait, tandis que vous seriez toujours en mesure d'utiliser thisRDD dans votre code (alors qu'il ne persistera plus en mémoire et serait recalculé chaque fois qu'il est interrogé)

13
0x0FFF

Réponse courte: Le code suivant devrait faire l'affaire:

import gc
del thisRDD
gc.collect()

Explication:

Même si vous utilisez PySpark, les données de votre RDD sont gérées du côté [Java, alors posons d'abord la même question, mais pour Java au lieu de Python:

Si j'utilise Java, et que je libère simplement toutes les références à mon RDD, est-ce suffisant pour le supprimer automatiquement?

Pour Java, la réponse est OUI, le RDD ne sera pas automatiquement dissocié quand il sera récupéré, selon cette réponse . (Apparemment, cette fonctionnalité a été ajoutée à Spark dans ce PR .)

OK, que se passe-t-il en Python? Si je supprime toutes les références à mon RDD en Python, est-ce que cela les supprime du côté Java?

PySpark utilise Py4J pour envoyer des objets de Python à Java et vice-versa. Selon les Py4J Memory Model Docs :

Une fois l'objet récupéré sur la Python VM (nombre de références == 0), la référence est supprimée sur la machine virtuelle Java

Mais prenez note: La suppression des références Python à votre RDD ne le fera pas immédiatement supprimé. Vous devez attendre que le récupérateur de déchets Python nettoie les références. Vous pouvez lire l'explication de Py4J pour plus de détails, où ils recommandent ce qui suit:

Un appel à gc.collect() fonctionne également généralement.

OK, revenons maintenant à votre question d'origine:

Les éléments suivants suffiraient-ils pour y parvenir:

del thisRDD

Presque. Vous devez supprimer la dernière référence (ie del thisRDD), Puis, si vous avez vraiment besoin que le RDD ne soit pas transpercé immédiatement **, appelez gc.collect().

** Eh bien, techniquement, cela supprimera immédiatement le référence côté Java, mais il y aura un léger délai jusqu'à ce que le garbage collector de Java exécute réellement le finaliseur du RDD et ainsi supprime les données.

8
Stuart Berg

Réponse courte: cela dépend.

Selon code source de pyspark v.1.3. , del thisRDD devrait suffire pour PipelinedRDD, qui est un RDD généré par Python mappeur/réducteur:

class PipelinedRDD(RDD):
    # ...
    def __del__(self):
        if self._broadcast:
            self._broadcast.unpersist()
            self._broadcast = None

RDD classe d'autre part, n'a pas __del__ méthode (alors qu'elle devrait probablement l'être), vous devez donc appeler la méthode unpersist par vous-même.

Modifier: __del__ la méthode a été supprimée dans this commit.

5
nonsleepr

Juste pour info, je recommanderais gc.collect() après del (si rdd prend beaucoup de mémoire).

3
joshsuihn