如何在PySpark中删除RDD以释放资源?

时间:2015-01-16 18:39:24

标签: python apache-spark pyspark

如果我有一个不再需要的RDD,如何从内存中删除它? 以下是否足以完成这项工作:

del thisRDD

谢谢!

4 个答案:

答案 0 :(得分:11)

不,del thisRDD是不够的,只会删除指向RDD的指针。您应该致电thisRDD.unpersist()以删除缓存的数据。

对于您的信息,Spark使用延迟计算模型,这意味着当您运行此代码时:

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

您确实没有任何缓存的数据,只会将其标记为' 进行缓存'在RDD执行计划中。你可以这样检查:

>>> 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]

但是当你在这个RDD上至少调用一次动作时,它会被缓存:

>>> 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]

您可以使用地址http://<driver_node>:4040/storage轻松检查Spark UI中的持久数据和持久性级别。你会看到那里del thisRDD不会改变这个RDD的持久性,但是thisRDD.unpersist()会解决它的问题,而你仍然可以在你的代码中使用这个RDD(虽然它赢了&#39 ; t不再存在于内存中,每次查询时都会重新计算)

答案 1 :(得分:5)

简短回答:这取决于。

根据pyspark v.1.3.0 source codedel thisRDD应该足够PipelinedRDD,这是由Python mapper / reducer生成的RDD:

class PipelinedRDD(RDD):
    # ...
    def __del__(self):
        if self._broadcast:
            self._broadcast.unpersist()
            self._broadcast = None
另一方面,

RDD课程没有__del__方法(虽然可能应该这样),所以你应该自己调用unpersist方法。

修改: __del__方法已在this提交中删除。

答案 2 :(得分:5)

简答:以下代码可以解决问题:

import gc
del thisRDD
gc.collect()

<强>解释

即使您使用的是PySpark,您的RDD数据也会在Java端进行管理,所以首先让我们提出相同的问题,但对于Java而不是Python:

如果我正在使用Java,而我只是释放对RDD的所有引用,那么它是否足以自动取消它?

对于Java,答案是肯定的,根据this answer,RDD在被垃圾收集时将自动取消存在。 (显然,this PR已将功能添加到Spark中。)

好的,Python会发生什么?如果我在Python中删除对RDD的所有引用,是否会导致它们在Java端被删除?

PySpark使用Py4J将对象从Python发送到Java,反之亦然。根据{{​​3}}:

  

在Python VM上对对象进行垃圾回收(引用计数== 0)后,将在Java VM上删除引用

但请注意:删除对RDD的Python引用不会导致立即删除。您必须等待Python垃圾收集器清理引用。您可以阅读Py4J的详细说明,他们建议如下:

  

拨打gc.collect()通常也有效。

好的,现在回到原来的问题:

  

以下是否足以完成这项工作:

del thisRDD

差不多。你应该删除对它的最后一个引用(即del thisRDD),然后,如果你真的需要立即取消使用RDD **,请致电{{1} }。

**从技术上讲,这将立即删除Java端的引用,但是在Java的垃圾收集器实际执行RDD之前会有一点延迟。终结者,从而使数据不存在。

答案 3 :(得分:2)

仅供参考, 我会在gc.collect()之后推荐del(如果rdd占用大量内存)。