默认情况下,有几个来源将RDD描述为 ephemeral (例如,this s/o answer) - 这意味着除非我们在其上调用cache()或persist(),否则它们不会留在内存中。
因此,假设我们的程序涉及一个短暂的(未由用户显式缓存)RDD,该RDD用于导致RDD实现的一些操作中。 我的问题是:Spark 丢弃物化短暂的RDD 立即 - 或者RDD是否可能留在内存中进行其他操作,即使我们从未要求它被缓存?
另外,如果短暂的RDD留在内存中,是不是因为某些LRU策略尚未将其踢出 - 或者也可能是因为调度优化?
我试图用下面的代码来解决这个问题 - 在4核机器上运行带有python 3.5和spark 1.6.0的Jupyter笔记本 - 但是我会很感激有人知道的答案肯定的。
import pyspark
sc = pyspark.SparkContext()
N = 1000000 # size of dataset
THRESHOLD = 100 # some constant
def f():
""" do not chache """
rdd = sc.parallelize(range(N))
for i in range(10):
print(rdd.filter(lambda x: x > i * THRESHOLD).count())
def g():
""" cache """
rdd = sc.parallelize(range(N)).cache()
for i in range(10):
print(rdd.filter(lambda x: x > i * THRESHOLD).count())
对于上面的两个函数,f()不会要求rdd持久化 - 但g()在开头就是这样。当我对两个函数foo()和boo()进行计时时,我得到了两个非常相似的性能,就好像cache()调用没有区别一样。 (事实上,使用缓存的那个更慢)。
%%timeit
f()
> 1 loops, best of 3: 2.19 s per loop
%%timeit
g()
> 1 loops, best of 3: 2.7 s per loop
实际上,即使修改f()来调用RDD上的unpersist()也不会改变。
def ff():
""" modified f() with explicit call to unpersist() """
rdd = sc.parallelize(range(N))
for i in range(10):
rdd.unpersist()
print(rdd.filter(lambda x: x > i * THRESHOLD).count())
%%timeit
ff()
> 1 loops, best of 3: 2.25 s per loop
unpersist()的文档声明它“将RDD标记为非持久性,并从内存和磁盘中删除[s]所有块。” 这是真的如此 - 或者当Spark知道它将在未来使用RDD时,Spark是否会忽略对unpersist的调用?
答案 0 :(得分:1)
这里的缓存没有任何价值。从RDD
创建range
非常便宜(每个分区只需要两个整数才能开始),并且您应用的操作无法从缓存中获益。 persist
应用于Java对象而不是Python对象,并且您的代码不会在RDD创建和第一次转换之间执行任何工作。
即使你忽略了所有这一点,这对于使用微小数据来说也是一项非常简单的任务。总成本很可能是由调度和沟通推动的。
如果您想查看缓存操作,请考虑以下示例:
from pyspark import SparkContext
import time
def f(x):
time.sleep(1)
return x
sc = SparkContext("local[5]")
rdd = sc.parallelize(range(50), 5).map(f)
rdd.cache()
%time rdd.count() # First run, no data cached ~10 s
## CPU times: user 16 ms, sys: 4 ms, total: 20 ms
## Wall time: 11.4 s
## 50
%time rdd.count() # Second time, task results fetched from cache
## CPU times: user 12 ms, sys: 0 ns, total: 12 ms
## Wall time: 114 ms
## 50
rdd.unpersist() # Data unpersisted
%time rdd.count() # Results recomputed ~10s
## CPU times: user 16 ms, sys: 0 ns, total: 16 ms
## Wall time: 10.1 s
## 50
虽然在这种简单的情况下,持久化行为是可预测的,但一般来说,缓存应被视为提示而不是契约。根据可用资源,任务输出可以保持或不保持,并且可以在没有任何用户干预的情况下从高速缓存中逐出。