spark(六)序列化及多线程问题

一、序列化

我们这里不讨论什么是序列化以及序列化有什么作用、序列化方式等问题。此处我们只讨论spark程序开发中序列化的一些问题
我们都知道spark程序实际计算时是在Executor上执行,因此Driver端的对象如果Executor要使用的话需要通过网络传输,因此对象一定要实现序列化接口,否则单机测试可能没问题,但是放到集群上就报序列化错误。
无论是直接使用,或通过广播发送,对象都要序列化。

二、序列化注意事项

先简要说一下scala中class object caseclass的区别

  • class与java中的class类似
  • object相当于单例类并且默认实现了序列化接口,其属性和方法都是静态的
  • case class 不用new对象,默认实现了equals、hashCode方法,默认是可以序列化的,支持模式匹配

接下来我们看一下如下测试代码(本地测试)

object SerializableTest {
  def main(args: Array[String]): Unit = {
    //本地测试使用local模式,内存不够用需要设置testingMemory,线上不用
    val conf: SparkConf = new SparkConf().setMaster("local[1]").setAppName("wordCount")
    conf.set("spark.testing.memory", "536870912") //后面的值大于512m即可
    val sc: SparkContext = new SparkContext(conf)
    val rdd1: RDD[Int] = sc.makeRDD(1 to 20,4)
    println("分区数:"+rdd1.getNumPartitions)
    val rules = MyRules2
    val resRdd = rdd1.mapPartitionsWithIndex((index,data) => {
      var ruleMap = rules.rulesMap
      val i: Int = ruleMap.getOrElse("hero", 0)
      val id: Long = Thread.currentThread().getId
      println(s"分区:$index,线程id $id,对象:$rules")
      data.map((_, "分区号:" + index))
    })
    println(resRdd.collect().toBuffer)
    sc.stop()
  }
}
class MyRules extends Serializable {
  val rulesMap: Map[String, Int] = Map("hero" -> 1, "king" -> 2)
}
object MyRules2 extends Serializable{
  val rulesMap: Map[String, Int] = Map("hero" -> 1, "king" -> 2)
}

val rules = MyRules2分别使用new MyRules()和MyRules2
new MyRules()打印结果:

分区:0,线程id 45,对象:com.hk.scala.MyRules@8accbb
分区:1,线程id 45,对象:com.hk.scala.MyRules@182e2da
分区:2,线程id 45,对象:com.hk.scala.MyRules@1f6093
分区:3,线程id 45,对象:com.hk.scala.MyRules@1d43451
ArrayBuffer((1,分区号:0), (2,分区号:0), 。。。)

MyRules2打印结果:

分区:0,线程id 45,对象:com.hk.scala.MyRules2$@a246af
分区:1,线程id 45,对象:com.hk.scala.MyRules2$@a246af
分区:2,线程id 45,对象:com.hk.scala.MyRules2$@a246af
分区:3,线程id 45,对象:com.hk.scala.MyRules2$@a246af
ArrayBuffer((1,分区号:0), (2,分区号:0), 。。。)

class在Executor端每个Task都会生成一个对象,object方式每个Executor上的多个task共用一个对象。
当然是用object可以直接在map方法中使用,这样Driver端就不用实例化这个类了

三、多线程

这里说的多线程问题指的是,一个spark任务最重会有多个Executor执行,每个Executor相当于一个进程,会有多个线程执行任务。如果在Driver端初始化一个unsafe类的对象,并且该对象为为多个task线程共用则可能出现多线程问题,比如SimpleDataFormat类就是非线程安全的,这一点在开发spark’程序时尤其要注意,因为本地可能无法复现问题。
解决方案:使用线程安全的类代替、加锁等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值