Spark源码解析(二)
来源:互联网 发布:网络暴力 维基百科 编辑:程序博客网 时间:2024/06/14 17:53
这次继续上次的地方,我这里只挑我个人感觉有意义的方法来讲,有些是内部的private方法,有些是展现给我们的外部可以调用的方法。这里主要讲的方法是他的内部方法withScope,方法如下:
/** * Execute a block of code in a scope such that all new RDDs created in this body will * be part of the same scope. For more detail, see {{org.apache.spark.rdd.RDDOperationScope}}. * * Note: Return statements are NOT allowed in the given body. */private[spark] def withScope[U](body: => U): U = RDDOperationScope.withScope[U](sc)(body)
我们可以个根据方法上上面的注释了解到:在一个范围内执行代码块,从而使得在这个body内创建的新的RDDS都是同一范围里面的不同部分。那么我们来看方法,首先声明是private方法,同时只在spark包中是有效的。然后定义了一个方法,名字叫做withScope。后面一开始我也有些懵逼,我是这么理解的(如果错了欢迎各位大神不吝赐教,小弟一定认真听教),这里定义了一个泛型,这个泛型是我们自定义的类型,继续往下看,这个函数需要一个参数,这个参数是一个函数。这样我们也就不难理解下面这段代码:
/** * Return a new RDD by applying a function to all elements of this RDD. */def map[U: ClassTag](f: T => U): RDD[U] = withScope { val cleanF = sc.clean(f) new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.map(cleanF))}这个是RDD中最重要的一个方法了,我们这里先不对此方法进行讲解,我们看后面,可能有些人会有些茫然,啥东西,咋一个方法后面跟了个大括号。其实是这样的,因为方法需要一个函数作为参数,而我们这里直接一个匿名函数的实现来作为参数,跟java中的一样。那么这就不难理解了。再回到上面的withScope代码中,我们继续往下看,类型U是RDDOperationScope中的一个方法,后面有两个括号,不要紧张,这只是scala中的curring。说白了这一步相当于传统代码中的两步,先传sc调用一个函数,再传body调用一个函数(嗯,我感觉下一篇文章有必要介绍一下这个curring,挺有意思的)。那我们点进去查看一下,代码如下:
/** * Execute the given body such that all RDDs created in this body will have the same scope. * The name of the scope will be the first method name in the stack trace that is not the * same as this method's. * * Note: Return statements are NOT allowed in body. */private[spark] def withScope[T]( sc: SparkContext, allowNesting: Boolean = false)(body: => T): T = { val ourMethodName = "withScope" val callerMethodName = Thread.currentThread.getStackTrace() .dropWhile(_.getMethodName != ourMethodName) .find(_.getMethodName != ourMethodName) .map(_.getMethodName) .getOrElse { // Log a warning just in case, but this should almost certainly never happen logWarning("No valid method name for this RDD operation scope!") "N/A" } withScope[T](sc, callerMethodName, allowNesting, ignoreParent = false)(body)}进入方法我们查看,这里方法又自定义了一个类型T,然后方法的第一个括号里面包含两个参数,有人问了,不对呀,刚才第一个括号里面不是只传了一个参数吗,不要着急,我们看第二个参数allowNesting/是否允许嵌套,他是一个Boolean类型的,而且有了默认值false,那么一切都解释的通了,调用方法时,这个参数可以不携带。然后后面第二个括号与之前传入的一致,然后定义了T类型,中间的代码大家可以略过,是用来获取一些变量。最后又调用了withScope,我们点进去查看,代码如下:
/** * Execute the given body such that all RDDs created in this body will have the same scope. * * If nesting is allowed, any subsequent calls to this method in the given body will instantiate * child scopes that are nested within our scope. Otherwise, these calls will take no effect. * * Additionally, the caller of this method may optionally ignore the configurations and scopes * set by the higher level caller. In this case, this method will ignore the parent caller's * intention to disallow nesting, and the new scope instantiated will not have a parent. This * is useful for scoping physical operations in Spark SQL, for instance. * * Note: Return statements are NOT allowed in body. */ private[spark] def withScope[T]( sc: SparkContext, name: String, allowNesting: Boolean, ignoreParent: Boolean)(body: => T): T = { // Save the old scope to restore it later val scopeKey = SparkContext.RDD_SCOPE_KEY val noOverrideKey = SparkContext.RDD_SCOPE_NO_OVERRIDE_KEY val oldScopeJson = sc.getLocalProperty(scopeKey) val oldScope = Option(oldScopeJson).map(RDDOperationScope.fromJson) val oldNoOverride = sc.getLocalProperty(noOverrideKey) try { if (ignoreParent) { // Ignore all parent settings and scopes and start afresh with our own root scope sc.setLocalProperty(scopeKey, new RDDOperationScope(name).toJson) } else if (sc.getLocalProperty(noOverrideKey) == null) { // Otherwise, set the scope only if the higher level caller allows us to do so sc.setLocalProperty(scopeKey, new RDDOperationScope(name, oldScope).toJson) } // Optionally disallow the child body to override our scope if (!allowNesting) { sc.setLocalProperty(noOverrideKey, "true") } body } finally { // Remember to restore any state that was modified before exiting sc.setLocalProperty(scopeKey, oldScopeJson) sc.setLocalProperty(noOverrideKey, oldNoOverride) } }}参数与之前传入的相一致。不要查其余无用代码,注意只看类型T返回的是什么?没错可能大家都已经看到了,返回的是传入的body。不要发飙,没人耍咱们,我个人理解,之前我们所做的所有准备都是为了控制body的上下文,也就是他这里面所谓的bodyScope,把他们控制在一个相同的范围内,说白了就是让所有在调用withScope方法内部创建的RDD都拥有相同的上下文环境,啥是上下文环境,sc呗,咋设置相同,setxxx都一样呗。这就是该代码的意义所在。那么到这里withScope代码介绍结束,希望各位路过的大牛指定不足之处。
感谢开源,让技术走近你我。
0 0
- Spark源码解析(二)
- Spark源码解析(一)
- Spark源码解析-spark-shell
- spark源码解析1
- spark rdd 源码解析
- Spark源码解析
- Spark源码解析:RDD
- Spark源码解析:DStream
- [spark] Checkpoint 源码解析
- Spark源码解析之任务提交(spark-submit)篇
- Spark源码-SparkContext源码解析
- Spark的standalone源码分析(二)
- Spark源码分析(二)RDD
- Spark源码系列(二)RDD详解
- Spark源码系列(二)RDD详解
- Spark源码系列(二)RDD详解
- Spark源码系列(二)RDD详解
- Spark源码系列(二)RDD详解
- 左偏树
- 使用qt开发ros应用
- * **ACM集训day11
- Vijos 1599 - 货币
- 二维数组作为函数参数---- error c2087:missing subscript
- Spark源码解析(二)
- hibernate与mysql映射类型对应表与mysql导入导出
- u盘在linux系统下文件只读方式的解决方案,linux基本常用命令之二十八dosfsck
- nodejs--path
- Maximum Subarray
- Android 开发神器系列(工具篇)之 Android WiFi ADB
- Android 中的 Service 全面总结
- 实现最多输入20个汉字(英文算半个汉字,奇数个英文算一个汉字),超过20个汉字后不能输入
- 史上最全的贝塞尔曲线(Bezier)全解(二):Android中曲线的简单绘制