Task的序列化问题


从Driver关联数据


一.创建一个Object的单例对象

知识点:Driver初始化一个object,这个单例对象要伴随着Task发送到Executor,但是一个Executor中只有一份,必须实现序列化接口, 有可能会出现线程安全问题.

  1. 创建一个单列对象代码如下:
package day05

/**
 * 必须序列化数据,因为是在Driver初始化,
 * 因为数据要伴随着Task的运算都是在Excutor端进行的,如果不序列化,会报错
 */
object RulesMapObj extends Serializable {
  val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}

  1. 关联Driver数据代码如下:
package day05

import java.net.{InetAddress, InetSocketAddress}

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}

object SerTest01 {
  def main(args: Array[String]): Unit = {
    val isLocal = args(0).toBoolean
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    val sc: SparkContext = new SparkContext(conf)
    //--------在Driver端初始化---------
    val rulesMap = RulesMapObj
    val lines: RDD[String] = sc.textFile(args(1))
    //对数据进行Map关联中文名称
    val wordAndProvince: RDD[(String, String, String, Int, Long, RulesMapObj.type)] = lines.map(word => {
      /**
       * 在Excutor端关联外部Driver端的数据,需要被序列化的数据才可以被调用
       */
      val province: String = rulesMap.rules(word)
      val partitionId = TaskContext.get().partitionId()
      val hostname = InetAddress.getLocalHost.getHostName
      val threadId = Thread.currentThread().getId
      (word, province, hostname, partitionId, threadId, rulesMap)
    })
    wordAndProvince.saveAsTextFile(args(2))
    sc.stop()

  }
}

二.实例化一个类的实例

知识点:Driver实例化一个类的实例,在函数内中引用了这个实例,伴随着Task发送到Executor,每个Task都独有一个单独的实例,必须实现序列化接口

  1. 实例化一个类的实例代码如下:
package day05

class RulesMapClass extends Serializable {
  val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}
  1. 关联Driver端数据代码如下:
package day05

import java.net.InetAddress

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext, TaskContext}

object SerTest02 {
  def main(args: Array[String]): Unit = {
    val isLocal = args(0).toBoolean
    //创建SparkConf,然后创建SparkContext
    val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
    if (isLocal) {
      conf.setMaster("local[*]")
    }
    val sc = new SparkContext(conf)
    //在Driver端初始化【new一个类的实例】
    val rulesMap = new RulesMapClass
    //sh
    val lines: RDD[String] = sc.textFile(args(1))
    //对数据进行map关联中文名称
    val wordAndProvince = lines.map(word => {
      //关联外部的规则
      //存在闭包:函数内部用到了一个函数外部的引用类型,函数式在Executor中被调用的
      //在Driver端引用的数据要伴随着Task一起发送到Executor中
      val province = rulesMap.rules(word)
      val partitionId = TaskContext.get().partitionId()
      val hostname = InetAddress.getLocalHost.getHostName
      val threadId = Thread.currentThread().getId
      (word, province, hostname, partitionId, threadId, rulesMap)
    })
    //将处理好的数据写回到HDFS
    wordAndProvince.saveAsTextFile(args(2))
    sc.stop()
  }
}

三:总结

  1. 关联Driver端数据,不管是Object和Class,都需要实现序列化接口.
  2. 如果关联数据是一个单列对象,那么一个Excutor中只有一个单列对象,如果关联数据是一个类的实列,那么Excutor端中,每一个Task对应一个单独的实列

从Excutor中关联数据

一.创建一个Object的单例对象

知识点:在Excutor使用一个Object,这个Object不用实现序列化,这个Object在Executor中初始化的,并且一个Executor中只有一份,有可能会出现线程安全问题

  1. 创建一个单列对象代码如下:
package day05

import java.net.InetAddress

object RulesMapObjNoSer {
  {

    val hostName = InetAddress.getLocalHost.getHostName

  }
  val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}



  1. 关联Excutor数据代码如下:
package day05
  import java.net.InetAddress
  import org.apache.spark.rdd.RDD
  import org.apache.spark.{SparkConf, SparkContext, TaskContext}

  object SerTest03 {
    def main(args: Array[String]): Unit = {
      val isLocal = args(0).toBoolean
      //创建SparkConf,然后创建SparkContext
      val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
      if (isLocal) {
        conf.setMaster("local[*]")
      }
      val sc = new SparkContext(conf)
      val lines: RDD[String] = sc.textFile(args(1))
      //对数据进行map关联中文名称
      val wordAndProvince = lines.map(word => {
        //关联外部的规则
        //RulesMapObjNoSer是在Executor端初始化的
        val province = RulesMapObjNoSer.rules(word)
        val partitionId = TaskContext.get().partitionId()
        val hostname = InetAddress.getLocalHost.getHostName
        val threadId = Thread.currentThread().getId
        (word, province, hostname, partitionId, threadId, RulesMapObjNoSer)
      })
      //将处理好的数据写回到HDFS
      wordAndProvince.saveAsTextFile(args(2))
      sc.stop()
    }
  }


二.实例化一个类的实例

知识点:在Excutor使用一个类的实例,这个实列对象不用实现序列化,这个实列类的对象在Executor中初始化的,并且一个Executor中每一个Task都单独有一份.

  1. 实例化一个类的实例代码如下:
package day05

class RulesMapClassNoSer {
  val rules = Map("ln" -> "辽宁省", "bj" -> "北京市", "sd" -> "山东省")
}

  1. 关联Excutor端数据代码如下:
package day05
  import java.net.InetAddress
  import org.apache.spark.rdd.RDD
  import org.apache.spark.{SparkConf, SparkContext, TaskContext}

  object SerTest04 {

    def main(args: Array[String]): Unit = {

      val isLocal = args(0).toBoolean
      //创建SparkConf,然后创建SparkContext
      val conf = new SparkConf().setAppName(this.getClass.getSimpleName)
      if (isLocal) {
        conf.setMaster("local[*]")
      }
      val sc = new SparkContext(conf)

      //sh
      val lines: RDD[String] = sc.textFile(args(1))
      //对数据进行map关联中文名称
      val wordAndProvince = lines.map(word => {
        //关联外部的规则
        //在Executor端创建的RulesMapClassNoSer
        val rulesMap = new RulesMapClassNoSer
        val province = rulesMap.rules(word)
        val partitionId = TaskContext.get().partitionId()
        val hostname = InetAddress.getLocalHost.getHostName
        val threadId = Thread.currentThread().getId
        (word, province, hostname, partitionId, threadId, rulesMap)
      })
      //将处理好的数据写回到HDFS
      wordAndProvince.saveAsTextFile(args(2))

      sc.stop()
    }


  }


三:总结

  1. 关联Excutor端数据,不管是Object和Class,都不需要实现序列化接口.
  2. 如果关联数据是一个单列对象,那么一个Excutor中只有一个单列对象,如果管数据是一个类的实列,那么Excutor端中,每一个Task对应一个单独的实列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值