持久化:
在spark里,多个rdd复用的时候建议对其持久化,这样就能只计算一次,如有必要还可以持久化两份,也就是所谓的双副本机制。(一般只建议用反序列内存或者序列内存,因为有时候去硬盘读的效果还不如重新计算)
广播变量:
rdd在task里运算,需要匹配一些外部变量的时候,就会去driver端拉取,如果变量过大,这时候就会消耗网络IO,同时每个task也会保存一份,在同一个execu上消耗了内存。可以通过广播变量将其从driver'端保存到每一个executor的内存中让task共享。(一般不建议超过1g)
累计器:
类似上诉,创建一个累加器,共享变量,注意该变量只能在driver端才能查看其存储的值(如scala的foreach里就不能用println查看)
scala版
package com.chen.spark
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
object broadcast {
def main(args:Array[String]):Unit = {
val conf = new SparkConf()
.setAppName("broadcast")
.setMaster("local")
val sc = new SparkContext(conf)
/**
* 广播变量
* 当多个task需要调用外部非RDd变量时,需要每一个去走io到driver拉取,并且每个task都要一份
* 广播之后,driver会将变量发送到每个executor内存中,对多core共用
* 节省网络io和内存(尤其是变量较大时)
*/
val factor = 2
val bc_factor =sc.broadcast(factor)
val numlistRDD = sc.parallelize(Array(1, 2, 3, 4), 1)
// 注意此处需要value函数来获取存储的值
val num_mul_2 = numlistRDD.map( x => x * bc_factor.value)
num_mul_2.foreach(x => println(x))
println("############# broadcast #############")
/**
* 累加器
* 效果大致类似,初始化一个值,来对他进行迭代操作
* 注意:task只能对他累加,driver才能对他拉取并获取里面的结果
*/
val num_accu = sc.accumulator(0)
val intRDD = sc.parallelize(Array(1, 2, 3, 4, 5))
// 通过内置函数add来累加
intRDD.foreach( i => num_accu.add(i))
// 驱动程序通过value来获取里面的结果
println(num_accu.value)
println("############# accumulator ########")
sc.stop()
}
}
Python版本
# -*- coding:utf-8 -*-
from pyspark import SparkConf
from pyspark import SparkContext
def CreateSparkContext():
sparkConf = SparkConf()
.setAppName("transformation_py")
.set("spark.ui.showConsoleProgress", "false")
sc = SparkContext(conf = sparkConf) # 不同于scala,这里必须指定conf来传参
print("master =" + sc.master)
return sc
if __name__ == "__main__":
sc = CreateSparkContext()
kv_fruit = sc.parallelize([(1, "banana"), (2, "apple"),
(3, "grape"), (4, "orange")])
# 下面要复用两次,所以这里实例了一下rdd缓存
# scala老版本里只能链式调用,新版本未测试
numlistRDD = sc.parallelize([1, 4, 2, 4, 3]).persist()
num_accu = sc.accumulator(0)
# 注意 在scala里我们是直接创建了一个非rdd变量
# 这里我们是先创建了一个kv Rdd,然后将其转换为Python独有的dict
fruitMap = kv_fruit.collectAsMap()
bc_fruitMap = sc.broadcast(fruitMap) # 是一个dict
fruit = numlistRDD.map(lambda x: bc_fruitMap.value[x]).collect()
print(fruit)
print("########## broadcast ########")
numlistRDD.foreach(lambda i : num_accu.add(i))
# drive端通过value】拉取
print(num_accu.value)
print("######## accumulator #########")
sc.stop()