Spark一路火花带闪电——Accumulator & Broadcast

Accumulator累加器

Accumulator简介

Accumulator是spark提供的累加器。在Spark中如果想在Task计算的时候统计某些事件的数量,使用filter/reduce也可以,但是使用累加器是一种更方便的方式,累加器一个比较经典的应用场景是用来在Spark Streaming应用中记录某些事件的数量。

陷阱及解决办法

	val num=sc.longAccumulator("name")
    val new_rdd2=rdd2.map(x=>{
      num.add(1)
      x+1
    })
    new_rdd2.count()
    new_rdd2.foreach(x=>print(x+" "))
    println("      "+num)

这样输出的num值为20,而不是10。spark中的一系列transform操作会构成一串长的任务链,此时需要通过一个action操作来触发,accumulator也是一样。因此在一个action操作之前,你调用value方法查看其数值,肯定是没有任何变化的。
所以在第一次count(action操作)之后,我们发现累加器的数值变成了10,是我们要的答案。
之后又对新产生的的new_rdd2进行了一次foreach(action操作),其实这个时候又执行了一次map(transform)操作,所以累加器又增加了10。最终获得的结果变成20。

解决办法

看了上面的分析,大家都有这种印象了,那就是使用累加器的过程中只能使用一次action的操作才能保证结果的准确性。

事实上,还是有解决方案的,只要将任务之间的依赖关系切断就可以了。什么方法有这种功能呢?你们肯定都想到了,cache,persist。调用这个方法的时候会将之前的依赖切除,后续的累加器就不会再被之前的transfrom操作影响到了。

new_rdd2.cache().count()

Broadcast广播变量

广播变量(broadcast varible)为只读变量,它有运行SparkContext的驱动程序创建后发送给参与计算的节点。对那些需要让工作节点高效地访问相同数据的应用场景,比如机器学习。我们可以在SparkContext上调用broadcast方法创建广播变量: 广播变量也可以被非驱动程序所在节点(即工作节点)访问,访问方法就是调用该变量的value方法,使用广播变量可以优化资源提高性能

广播变量的优势:是因为不是每个task一份变量副本,而是变成每个节点的executor才一份副本。这样的话,就可以让变量产生的副本大大减少。 广播变量,初始的时候,就在Drvier上有一份副本。task在运行的时候,想要使用广播变量中的数据,此时首先会在自己本地的Executor对应的BlockManager中,尝试获取变量副本;如果本地没有,BlockManager,也许会从远程的Driver上面去获取变量副本;也有可能从距离比较近的其他节点的Executor的BlockManager上去获取,并保存在本地的BlockManager中;BlockManager负责管理某个Executor对应的内存和磁盘上的数据,此后这个executor上的task,都会直接使用本地的BlockManager中的副本。

rdd1=sc.parallelize([1,2,3,4,5])

num=3

broadcastFactor=sc.broadcast(num)

rdd2=rdd1.map(lambda x:x*broadcastFactor.value)

rdd2.foreach(lambda x:print(x))

猜你喜欢

转载自blog.csdn.net/No_Game_No_Life_/article/details/89307445