1. 前述
  1. 在上一章节Spark(十五)Executor执行Task的原理与源码分析我们解析了执行Task之前的一些准备工作,但是还没有正真进入Task的执行程序。在上一章节的解析中,在最后Task里的run方法中调用了抽象方法runTask方法,而我们说了,Task是一个抽象类,而runTask方法也是一个抽象方法,所以Task执行的具体逻辑是有Task的子类实现的,实现类Task抽象类的子类有两种,一个是ShuffleMapTask,一个是ResultTask、所以下边我们将对这两个类进行详细的解析,理解Task执行的具体细节。
  1. ShuffleMapTask原理解析:这类的作用是将RDD的每个Partition拆分成多个buckets(存储桶或者存储区)(基于ShuffleDependency中指定的分区)
  1. ShuffleMapTaskrunTask方法:
//该方法的作用执行Task,然后将结果返回给调度器
 //其中MapStatus封装了块管理器的地址,以及每个reduce的输出大小
 //以便于传递reduce的任务
 override def runTask(context: TaskContext): MapStatus = {
   //记录反序列化RDD的开始时间
    val deserializeStartTime = System.currentTimeMillis()
    //创建一个序列化器
    val ser = SparkEnv.get.closureSerializer.newInstance()
     // 反序列化广播变量来的得到RDD
    val (rdd, dep) = ser.deserialize[(RDD[_], ShuffleDependency[_, _, _])](
      ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
    _executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime

    metrics = Some(context.taskMetrics)
    var writer: ShuffleWriter[Any, Any] = null
    try {
      //获取ShuffleManager
      val manager = SparkEnv.get.shuffleManager
      //利用ShuffleManager获取ShuffleWriter,ShuffleWriter的功能就是将Task计算的结果
      //持久化到shuffle文件中,作为子Stage的输入
      writer = manager.getWriter[Any, Any](dep.shuffleHandle, partitionId, context)
      //通过ShuffleWriter将结果进行持久化到shuffle文件中,作为子Stage的输入
      //rdd.iterator(partition, context)这个方法里就会执行我们自己编写的业务逻辑代码
      writer.write(rdd.iterator(partition, context).asInstanceOf[Iterator[_ <: Product2[Any, Any]]])
      //关闭writer,将元数据写入MapStatus中,然后返回
      writer.stop(success = true).get
    } catch {
      case e: Exception =>
        try {
          if (writer != null) {
            writer.stop(success = false)
          }
        } catch {
          case e: Exception =>
            log.debug("Could not stop writer", e)
        }
        throw e
    }
  }
  1. RDDiterator方法,
final def iterator(split: Partition, context: TaskContext): Iterator[T] = {
    //判断存储级别,如果存储不为None,那么就会从缓存中取出Partition
    if (storageLevel != StorageLevel.NONE) {
      SparkEnv.get.cacheManager.getOrCompute(this, split, context, storageLevel)
    } else {
      //Partition没有缓存,就调用这个方法
      computeOrReadCheckpoint(split, context)
    }
}
  1. RDDcomputeOrReadCheckpoint方法,
private[spark] def computeOrReadCheckpoint(split: Partition, context: TaskContext): Iterator[T] ={
    if (isCheckpointedAndMaterialized) {
      firstParent[T].iterator(split, context)
    } else {
      //调用RDD的compute方法开始执行Task
      compute(split, context)
    }
}
  1. MapPartitionsRDDcompute方法
override def compute(split: Partition, context: TaskContext): Iterator[U] =
    //该方法就是Spark执行了我们自己写的处理逻辑代码
    //f:Spark封装了我们的逻辑代码
    f(context, split.index, firstParent[T].iterator(split, context))
  1. ResultTask runTask原理解析
  1. ResultTaskrunTask方法,因为ResultTask执行的结果就是最终结果,要不返回,要不持久化,所以它的处理逻辑很简单。
override def runTask(context: TaskContext): U = {
    //记录反序列化RDD的开始时间
    val deserializeStartTime = System.currentTimeMillis()
    /创建一个序列化器
    val ser = SparkEnv.get.closureSerializer.newInstance()
    // 反序列化广播变量来的得到RDD
    val (rdd, func) = ser.deserialize[(RDD[T], (TaskContext, Iterator[T]) => U)](
      ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
    _executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime

    metrics = Some(context.taskMetrics)
    //因为ResultTask执行后的结果不会给任何其他的Task用,所以就直接调用rdd的iterator方法
    //执行我们自己定义的逻辑代码
    func(context, rdd.iterator(partition, context))
  }
  1. RDDiterator方法
final def iterator(split: Partition, context: TaskContext): Iterator[T] = {
    if (storageLevel != StorageLevel.NONE) {
      SparkEnv.get.cacheManager.getOrCompute(this, split, context, storageLevel)
    } else {
      computeOrReadCheckpoint(split, context)
    }
  }
  1. RDDcomputeOrReadCheckpoint方法,
private[spark] def computeOrReadCheckpoint(split: Partition, context: TaskContext): Iterator[T] = {
    if (isCheckpointedAndMaterialized) {
      firstParent[T].iterator(split, context)
    } else {
      compute(split, context)
    }
  }
  1. ShuffleRDDcompute方法
override def compute(split: Partition, context: TaskContext): Iterator[(K, C)] = {
    val dep = dependencies.head.asInstanceOf[ShuffleDependency[K, V, C]]
    SparkEnv.get.shuffleManager.getReader(dep.shuffleHandle, split.index, split.index + 1, context)
      .read()
      .asInstanceOf[Iterator[(K, C)]]
  }