2、一个应用程序中有多少个行动算子就会创建多少个job作业;一个job作业中一个宽依赖会划分一个stage阶段;同一个stage阶段中最后一个算子有多少个分区这个stage就有多少个task,因为窄依赖每个分区任务是并行执行的,没有必要每个算子的一个分区启动一个task任务。如图所示阶段2最后一个map算子是对应5个分区,reducebykey是3个分区,总共是8个task任务。
3、当一个rdd的数据需要打乱重组然后分配到下一个rdd时就产生shuffle阶段,宽依赖就是以shuffle进行划分的。
一、关系概览
二、Job/Stage/Task关系
一个Spark程序可以被划分为一个或多个Job,划分的依据是RDD的Action算子,每遇到一个RDD的Action *** 作就生成一个新的Job。
每个spark Job在具体执行过程中因为shuffle的存在,需要将其划分为一个或多个可以并行计算的stage,划分的依据是RDD间的Dependency关系,当遇到Wide Dependency时因需要进行shuffle *** 作,这涉及到了不同Partition之间进行数据合并,故以此为界划分不同的Stage。
Stage是由Task组组成的并行计算,因此每个stage中可能存在多个Task,这些Task执行相同的程序逻辑,只是它们 *** 作的数据不同。
一般RDD的一个Partition对应一个Task,Task可以分为ResultTask和ShuffleMapTask。
补充说明:
多个Stage可以并行(S1/S2),除非Stage之间存在依赖关系(S3依赖S1+S2)。
三、RDD/Partition/Records/Task关系
通常一个RDD被划分为一个或多个Partition,Partition是Spark进行数据处理的基本单位,一般来说一个Partition对应一个Task,而一个Partition中通常包含数据集中的多条记录(Record)。
注意不同Partition中包含的记录数可能不同。Partition的数目可以在创建RDD时指定,也可以通过reparation和coalesce等算子重新进行划分。
通常在进行shuffle的时候也会重新进行分区,这是对于key-valueRDD,Spark通常根据RDD中的Partitioner来进行分区,目前Spark中实现的Partitioner有两种:HashPartitioner和RangePartitioner,当然也可以实现自定义的Partitioner,只需要继承抽象类Partitioner并实现numPartitions and getPartition(key: Any)即可。
四、运行层次图
进程(程序):是静态概念,一个class文件、一个exe文件
线程:是一个程序里面不同的执行路径
相关给概念解释:
程序执行过程:把程序的代码放到内存的代码区里面,这时候一个进程已经产生,但是还没有开始执行。平时说的进程的执行是指进程里面主线程开始执行了(main方法执行)。
举例说明:
public class ThreadTest {public static void m1() {
System.out.println("m1")
}
public static void m2() {
System.out.println("m2")
}
public static void m3() {
m1()
m2()
}
public static void main(String[] args) {
m3()
}}
程序中的路径或者线程也就是main方法(共一条):
路径图解释:
Main方法执行到m3()语句的时候开始调用m3的方法,此时main方法不会继续往下执行,而是等到m3方法执行结束以后才继续执行。在m3方法中执行到m1( )语句的时候会调用m1的方法,此时m2( )语句不会继续往下执行,而是等到m1方法的返回,才继续执行m2的方法。m2方法的返回以后m3继续执行,等到m3返回以后main方法继续执行,这是完整的一条路径也就是一个线程。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)