Spark缓存

Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或缓存多个数据集。当持久化某个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍生出的RDD进行的其他动作中重用。这使得后续的动作变得更加迅速。RDD相关的持久化和缓存,是Spark最重要的特征之一。

RDD通过persist方法或cache方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是触发后面的行动算子时,该RDD将会被缓存在计算节点的内存中,并供以后重用。

不带缓存的计算示例

理论介绍完了,下面我们来看看例子,来对比观察使用缓存和不用缓存的效率区别。

以下通过一个计算斐波那契数列(1,1,2,3,5,8,13,....)第n项的例子,来展示 Spark 中cache方法的运行效果。

先来看看一段代码。

import org.apache.spark.storage.StorageLevel

import org.apache.spark.{SparkConf, SparkContext}



object Cache {

  def main(args: Array[String]): Unit = {

    // 配置Spark

    val conf = new SparkConf().setAppName("CacheExample").setMaster("local[*]")

    val sc = new SparkContext(conf)

//    conf.set("spark.local.dir", "_cache")

sc.setLogLevel("WARN")

    // 创建一个包含大量随机数的 RDD

    val largeRDD = sc.parallelize(1 to 1000*1000*10).map(_ => scala.util.Random.nextInt(1000))



    // 定义一个复杂的转换函数

    def complexTransformation(num: Int): Int = {

      var result = num

      for (_ <- 1 to 1000) {

        result = result * 2 % 1000

      }

      result

    }



    // 不使用 cache 的情况

    val nonCachedRDD = largeRDD.map(complexTransformation)



    // 第一次触发行动算子,计算并统计时间

    val startTime1 = System.currentTimeMillis()

    val result1 = nonCachedRDD.collect()

    val endTime1 = System.currentTimeMillis()

    println(s"不使用 cache 第一次计算耗时: ${endTime1 - startTime1} 毫秒")



    // 第二次触发行动算子,计算并统计时间

    val startTime2 = System.currentTimeMillis()

    val result2 = nonCachedRDD.collect()

    val endTime2 = System.currentTimeMillis()

    println(s"不使用 cache 第二次计算耗时: ${endTime2 - startTime2} 毫秒")

    sc.stop()

  }

}

核心代码说明:

1.map算子是转换算子,并不会导致真正的计算

2.第一次调用collect和第二调用collect花的时间基本一致。这就是没有缓存的效果。

带缓存的计算示例-cache

【教师讲解cache的格式,并直接添加进来】,下面我们引入spark的cache方法。

在 Scala 里,cache 方法定义于 org.apache.spark.rdd.RDD 类中,其方法签名如下:

scala

def cache(): this.type

返回类型:this.type,这表明返回的是调用该方法的 RDD 自身,只不过这个 RDD 已经被标记为需要缓存。

参数:此方法没有参数。

// 使用 cache 的情况

    val cachedRDD = largeRDD.map(complexTransformation).cache()

   



    // 第一次触发行动算子,计算并统计时间

    val startTime3 = System.currentTimeMillis()

    val result3 = cachedRDD.collect()

    val endTime3 = System.currentTimeMillis()

    println(s"使用 cache 第一次计算耗时: ${endTime3 - startTime3} 毫秒")



    // 第二次触发行动算子,计算并统计时间

    val startTime4 = System.currentTimeMillis()

    val result4 = cachedRDD.collect()

    val endTime4 = System.currentTimeMillis()

    println(s"使用 cache 第二次计算耗时: ${endTime4 - startTime4} 毫秒")



    println(s"spark.local.dir 的值: ${conf.get("spark.local.dir")}")

    sc.stop()

核心代码说明:

第一次调用collect时,程序需要对RDD中的每个元素执行fibonacci函数进行计算,这涉及到递归运算,比较耗时。

第二次调用collect时,因为之前已经调用了cache方法,并且结果已被缓存,所以不需要再次执行计算,直接从缓存中读取数据。通过对比两次计算的耗时,可以明显发现第二次计算耗时会远小于第一次(在数据量较大或计算复杂时效果更显著),这就体现了cache方法缓存计算结果、避免重复计算、提升后续操作速度的作用 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值