版權聲明:本文爲博主原創文章,未經博主允許不得轉載!!
歡迎訪問: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