版权声明:本文为博主原创文章,未经博主允许不得转载!!
欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81266889
交流QQ: 824203453
1.java中的序列化的回顾
val stream = new ObjectOutputStream(new FileOutputStream("f:/person.txt"))
val p1 = new Person("x1", 28)
stream.writeObject(p1)
stream.writeInt(10)
stream.flush()
val out = new ObjectInputStream(new FileInputStream("f:/person.txt"))
val obj = out.readObject()
val p2 = obj.asInstanceOf[Person]
println(p1 == p2)
println(out.readInt())
2.Spark序列化:
2.1 序列化方案:
Spark中提供了2种序列化方案:
Spark中默认使用的是java的序列化机制,JavaSerializer
如果需要使用Kryo序列化,需要进行注册。
2.2 Kryo 序列化
// 设置kryo序列化
conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
conf.registerKryoClasses(Array(classOf[MyClass1]))
kryo序列化特点:
速度快,占用资源少。
需要注册
3.Spark序列化位置验证
3.1 在函数中调用
如果直接在函数中调用类的实例对象或者 object,
该类或者对象不需要进行序列化。
原因:数据并没有driver和executor之间传输,类是在executor中实例化的
task在处理每一条数据的时候,
如果使用的是类,处理每一条数据时都需要对类进行实例化。(同一个task中的每一条数据,对应着一个实例)
// 类的定义
class MyTask {
val mp = Map("hadoop" -> 10, "spark" -> 1000)
}
val f1 = sc.textFile(args(0))
val result = f1.map(t => {
// 创建一个对象 该对象在哪里创建? executor driver task?
val mt = new MyTask()
// 打印当前的对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
// 通过该对象的集合获取值
mt.mp.getOrElse(t, 0)
// 获取当前的主机名
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
(hostName, threadName ,mt.mp.getOrElse(t,0),mt.toString)
)})
result.saveAsTextFile(args(1))
sc.stop()
如果使用的是object,object是单例的,所以在一个进程中,只需要有一个实例就可以了。
object是在executor中,一个executor进程中实例化了一次。
val f1 = sc.textFile(args(0))
val result = f1.map(t => {
// 获取当前的主机名
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
// 直接在函数中引用object
(hostName, threadName, MyTaskObj.mp.getOrElse(t, 0), MyTaskObj.toString)
})
result.saveAsTextFile(args(1))
sc.stop()
// object
object MyTaskObj extends Serializable{
val mp = Map("hadoop" -> 10, "spark" -> 1000)
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
println(s"###########-----${hostName},${threadName}---###########")
}
3.2 闭包引用
当我们在函数内部使用了一个外部的引用,该引用对象对应的类或者object必须要进行序列化。 extends Serializable
在driver端的对象和executor中的对象,不是同一个,每次在一个task中,进行反序列化,获取到了新的对象。
如果使用的是类:
类是在driver端实例化了,然后序列化发送给executor,在executor中,每一个task处理的所有数据,对应着一个新的实例对象。(同一个task中的所有数据,共用一个实例)
val f1 = sc.textFile(args(0))
// 在driver端创建一个类的实例对象 该类必须实现序列化
val mt = new MyTask()
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {
// 获取当前的主机名
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
(hostName, threadName, mt.mp.getOrElse(t, 0), mt.toString)
})
result.saveAsTextFile(args(1))
sc.stop()
// 序列化
class MyTask extends Serializable{
val mp = Map("hadoop" -> 10, "spark" -> 1000)
}
使用的是object:
object 也是在driver端实例化的,然后序列化发送给executor,但是在executor中,每一个executor中的所有task共用一个实例对象,不同的executor之间,对象是不相同的。
(同一个executor中的数据,共用一个实例)
val f1 = sc.textFile(args(0))
// 在driver端定义一个对象
val mt = MyTaskObj
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {
// 获取当前的主机名
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
(hostName, threadName, mt.mp.getOrElse(t, 0), mt.toString)
})
result.saveAsTextFile(args(1))
sc.stop()
// 使用对象
object MyTaskObj extends Serializable{
val mp = Map("hadoop" -> 10, "spark" -> 1000)
}
当在函数内部使用了一个外部的引用,就生成一个闭包。
闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。比如说,在函数中使用定义在其外的局部变量,这就形成了一个闭包。 var sum = 0 List(1,2,3,4,5).foreach(x => sum += x) 在scala中,闭包捕获了变量本身,而不是变量的值。 闭包的本质:代码块+上下文 |
3.3 广播变量
当把一个类的实例进行广播时,该类必须要实现序列化
同一个executor中的所有task处理不同数据时,共享一份数据。
val f1 = sc.textFile(args(0))
// 在driver端创建一个类的实例对象
val mt = new MyTask()
val bc = sc.broadcast(mt)
// 打印当前的实例对象
println(s"@@@@@@@@@@@@@+++${mt.toString}+++@@@@@@@@@@@@@")
val result = f1.map(t => {
val newTask = bc.value
// 获取当前的主机名
val hostName = InetAddress.getLocalHost.getHostName
// 获取当前的线程名
val threadName = Thread.currentThread().getName
(hostName, threadName, newTask.mp.getOrElse(t, 0), newTask.toString)
})
result.saveAsTextFile(args(1))
sc.stop()
版权声明:本文为博主原创文章,未经博主允许不得转载!!
欢迎访问:https://blog.csdn.net/qq_21439395/article/details/81266889
交流QQ: 824203453