讲讲自己对于ShuffleMapTask和ResultTask的区别
简单来说两者都是Task类的子类,不同的是操作类型,前者的操作类型是MapStaus类,是在shuffle map stage生成的,后者的操作类型是数据,是在final stage生成的,多说一句,所谓的Spark基于内存存储中间数据应该就是存储MapStatus(分区的映射状态),鉴于它们都是Task类的子类,因此对Task类的核心方法----runTask方法进行简单讲述下
Shuffle map task首先生成和该任务相关的BlockObjectWriter对象,BlockObjectWriter用来将分区写入磁盘中,这就和之前提到的BlockManager的内容扯上了关系,之后根据生成的BlockObjectWriter对象得到任务的压缩大小,最后将BlockManagerId和任务的压缩大小封装在MapStatus对象中,存储MapStatus即可,该MapStatus对象又会作为其他shuffle map stage的输入,紧接着Shuffle map task会调用TaskContext类的executeOnCompleteCallbacks()函数,执行存储在onCompleteCallbacks数组缓存中的函数,这些函数就是我们应用程序中所涉及到的函数,在我们每生成一个任务的过程时,该任务的TaskContext对象就会将在这个过程中应用到的函数(我觉得这些函数就是我们应用程序中所编写的函数)添加到onCompleteCallbacks中
而ResultTask的runTask过程就相对来说比较易于理解,因为ResultTask不牵涉shuffle过程,它是一个job的最后阶段,一个job只会有一个ResultTask,在runTask()方法中首先ResultTask执行传递给finalStage的函数func(因为resultTask只会在finalStage中生成),之后ResultTask会调用TaskContext类的executeOnCompleteCallbacks()函数,其实关于ShuffleMapTask和ResultTask我的理解始终有所模糊,不过暂且理解如下,希望日后能够得到更进一步的理解
通过上面的讲述,我认为整个stage或者任务的提交应该都是基于job的提交,只有job提交后才能进行stage的划分,任务集的提交,任务的执行,因此接下来讲讲DAGScheduler中的job提交部分,这部分结束之后才算得上是完成了整个spark的调度过程
应用程序中RDD有许多的动作函数,如collect()等,在前面RDD章节中已经介绍过了,正是由于这些动作函数,触发了job的提交,进而触发了整个调度过程,可以借助下图进行理解:
其中:finalStage是一个Stage类的对象,它通过newStage()方法生成,是整个job过程的最后一个stage
之后的步骤就可参照上述DAGScheduler划分stage的那部分了,如此就基本上完成了整个DAGScheduler的调度过程
在之前的章节中已经对submitStage等方法做了解释,现在稍微讲述下runLocally()方法的实现思想
runLocally()方法是在finalStage没有父stage,且允许本地运行,同时RDD只有一个分区的情况下才会调用,它生成一个线程对象(Thread),并且重写了Thread类的run方法(即调用DAGScheduler中的runLocallyWithinThread()方法,该方法就是生成一个TaskContext类对象,之后执行触发这个job的动作函数,动作函数的参数即为刚刚生成的TaskContext类对象以及其他),之后让线程start(即允许重写的run()方法)即可
DAGScheduler中还有其他方法,基本上就是用于处理各种事件,如任务集失败等等,这可以联想到之前讲TaskSetManager时提到过TaskSetManager用来处理各种任务集所发生的事件时就是调用DAGScheduler的相应方法,在这里就不继续讲下去了,点到为止,我主要是想搞明白DAGScheduler如何划分stage以及如何提交任务集给TaskScheduler,因此这部分就讲到这里,虽然还有很多讲得不太清楚的地方,因此希望可以通过日后的学习及运用加深理解
未完待续。。。
PS:觉得楷体不太适合博文。。换种试试。。。
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。