|NO.Z.00091|——————————|BigDataEnd|——|Hadoop&Spark.V07|——|Spark.v07|Spark 原理 源码|作业执行原理&Stage划分&提交ResultStage|
一、Stage划分
### --- 提交ResultStage
~~~     submitStage 方法会通过入参 ResultStage 逐层获取父stage,
~~~     再从最上游stage开始逐步调用TaskScheduler.submitTasks 方法提交task集合,
~~~     最后才提交ResultStage的task集合。
~~~     先调用getMissingParentStages来获取是否有未提交的父stages。
~~~     若有,则依次递归提交父stages,并将missing加入到waitingStages中。
~~~     对于要依次提交的父stage,也是如此;
~~~     若missing存在未提交的父stages,则先提交父stages;
~~~     这时会调用submitMissingTasks(stage, jobId.get),参数就是missing及其对应的jobId.get。
~~~     这个函数便是将stage与taskSet对应起来,
~~~     然后DAGScheduler将taskSet提交给TaskScheduler去执行的实施者。二、源码提取说明
### --- 源码提取说明
~~~     # 源码提取说明:DAGScheduler.scala
~~~     # 1061行~1082行
  private def submitStage(stage: Stage) {
    // 获取当前Stage对应的Job的ID
    val jobId = activeJobForStage(stage)
    if (jobId.isDefined) { // Job ID是定义的
      logDebug("submitStage(" + stage + ")")
      if (!waitingStages(stage) && !runningStages(stage) && !failedStages(stage)) { //当前Stage未提交
        // 获取当前Stage的所有未提交的父Stage
        val missing = getMissingParentStages(stage).sortBy(_.id)
        logDebug("missing: " + missing)
        if (missing.isEmpty) { // 不存在未提交的父Stage
           logInfo("Submitting " + stage + " (" + stage.rdd + "), which has no missing parents") 
          // 提交当前Stage所有未提交的Task
          submitMissingTasks(stage, jobId.get)
        } else { // 存在未提交的父Stage
          // 提交所有未提交的父Stage
          for (parent <- missing) {
            submitStage(parent)
            
            } 
          // 并且将当前Stage加入waitingStages集合中,当前Stage必须等待所有父Stage执行完成
          waitingStages += stage
        }
      }
    } else { // Job ID未定义,放弃提交当前Stage
      abortStage(stage, "No active job for stage " + stage.id, None)
    }
  }~~~     # 源码提取说明:DAGScheduler.scala
~~~     # 550行~574行
  // 获取Stage的所有未提交的父Stage
  // private def getMissingParentStages(stage: Stage): List[Stage] = {
  val missing = new HashSet[Stage]
  val visited = new HashSet[RDD[_]]
  // We are manually maintaining a stack here to prevent StackOverflowError
  // caused by recursively visiting
  val waitingForVisit = new Stack[RDD[_]]
  // 定义visit()方法
  def visit(rdd: RDD[_]) {
    // 判断是否已经处理过
    if (!visited(rdd)) { // 未处理过
      // 添加到已处理集合进行记录
      visited += rdd
      /**
       * 获取RDD各个分区的TaskLocation序列,判断是否包含Nil。
       * Stage的RDD的分区中存在没有对应TaskLocation序列的分区,
       * 则说明当前Stage的某个上游ShuffleMapStage的某个分区任务未执行。
       */
      val rddHasUncachedPartitions = getCacheLocs(rdd).contains(Nil)
      if (rddHasUncachedPartitions) { // TaskLocation序列包含Nil
        // 遍历该rdd的所有依赖
        for (dep <- rdd.dependencies) {
          dep match {
            case shufDep: ShuffleDependency[_, _, _] => // 是ShuffleDependency
              // 获取该ShuffleDependency的上游第一个提交的ShuffleMapStage
              val mapStage = getOrCreateShuffleMapStage(shufDep, stage.firstJobId)
              if (!mapStage.isAvailable) { // 该ShuffleMapStage不可用
                // 将其添加到missing集合进行记录
                missing += mapStage
              } 
            case narrowDep: NarrowDependency[_] => // 是NarrowDependency
              // 将该窄依赖的rdd压入waitingForVisit栈中
            waitingForVisit.push(narrowDep.rdd)
          }
        }
      }
    }
  }Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
                                                                                                                                                   ——W.S.Landor
 
                    
                     
                    
                 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号 
