前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >纯函数式堆(纯函数式优先级队列)part three ---- bootstrapping (自举)

纯函数式堆(纯函数式优先级队列)part three ---- bootstrapping (自举)

作者头像
Ldpe2G
发布于 2018-07-09 06:59:30
发布于 2018-07-09 06:59:30
53900
代码可运行
举报
运行总次数:0
代码可运行

前言:

这篇文章是基于我看过的一篇论文,主要是关于函数式数据结构,函数式堆(优先级队列),

我会以自己的理解写下来,然后论文中出现的代码将会使用scala这们语言。

论文链接:   Optimal Purely Functional Priority Queues,另外一个链接:   论文。

正文:

紧接patr two,

这章介绍对合并和查找操作的优化,使得最终插入,合并,查找最小的时间复杂度均为O(1)。

这里我跳过了论文中增加全局根那一节,因为bootstrap这一节包含了增加全局根的内容。

bootstrapping Heap:

首先假设原始堆的定义是:

a表示堆中存储的元素类型。

然后给出最终的bootstrap堆的定义:

这里BHa表示bootstrap堆或者是一个空堆或者是Ra(R代表root)

Ra表示一个元素a和一个原始堆H包含其他非空的bootstrap堆Ra的元组。

a其实就是保存堆中最小的元素,这样查找最小的操作时间复杂度就变为O(1)

而这里原始堆H选用的当然就是斜二项堆,这样保持插入的时间复杂度O(1)

而bootstrap堆的合并操作其实就变成将一个bootstrap堆作为元素插入到斜二项堆中。

这里对于斜二项堆中保存的元素类型就是Ra。

这里的定义有递归的感觉,读者最好是熟悉了前两章的内容再来看这章,

因为我是精简很多内容,所以如果觉得我说的不清楚的,可以看看论文解释的很详细。

我觉得看论文中的代码对于我的理解很有帮助。

现在来描述bootstrap堆的操作,这里用f来表示斜二项堆HRa的操作,F来表示bootstrap堆BHa的操作。

FINDEMIN( <x, sh> )              =  x ,  <x, sh>就是Ra的表示, sh 表示HRa,就是斜二项堆;

INSERT( x, sh )                      =  MELD( <x, empty>, sh )

MELD( <x1, sh1>, <x2, sh2> ) = < x1, insert( <x2, sh2>, sh1 ) >   if  x1 <= x2

MELD( <x1, sh1>, <x2, sh2> ) = < x2, insert( <x1, sh1>, sh2 ) >   if  x2 < x1

DELETEMIN( <x, sh> )             = <y, meld( sh1, sh2 )>

                                               其中 <y, sh1> = findMin( sh )

                                                           sh2  = deleteMin( sh )

我们可以看到

查找最小的操作FINDMIN明显时间复杂度为O(1),而对于合并操作MELD,时间复杂度的为O(1),因为斜二项堆的

插入操作是O(1),而插入操作其实就是化成合并操作MELD,所以时间复杂度为O(1),而对于删除最小操作,时间复杂

度是O(log n),因为对于斜二项堆findMin和deleteMin这两项的操作时间复杂度都是O(log n)

bootsrtap堆的定义:

由于论文中的代码用的是ML语言,将之改成scala花了不少功夫:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
trait BootstrapSkewBinomialHeap extends Heap {
        //Rooted定义了斜二项堆的元素类型
	trait Rooted extends Heap {
	        //RootQ就是上面定义的Ra,h表示堆的类型
                //当该trait和斜二项堆trait混合的时候,就表示为斜二项堆的堆类型H
                //就是下面的RootedHeap
	        case class RootQ( x: BootstrapSkewBinomialHeap.this.A, h: H)
	
		override type A = RootQ
		
		object AgeOrdering extends Ordering[RootQ] {
			def compare( a: RootQ, b: RootQ ) = 
				BootstrapSkewBinomialHeap.this.ord.compare( a.x, b.x )
		}
		//因为堆的元素类型变为RootQ,所以需提供相应的元素比较方法
		override def ord = AgeOrdering
		
	}	
        //root斜二项堆
	val RootedHeap = new Rooted with SkewBinomialHeap       
        //表示空bootstrap堆
	case class Empty( msg: String )	
        
	//bootstrap堆的定义,或者是一个空堆,或者是一个RootQ类型
        //用scala的Either类型来描述
	override type H = Either[Empty, RootedHeap.RootQ]
	
	override def empty = Left( Empty( "empty" ) )

	override def isEmpty( ts: H ) = ts match {
  	  case Left( _ ) => true
  	  case Right( _ ) => false
  	}  	
        //bootstrap堆的插入操作可化为合并操作
  	override def insert( x: A, ts: H ): H = 
			meld( Right( RootedHeap.RootQ( x, RootedHeap.empty ) ), ts )  	
        
  	override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match {
  	  case ( Left( Empty( _ ) ), ts ) => ts
  	  case ( ts, Left( Empty( _ ) ) ) => ts
  	  case ( Right( RootedHeap.RootQ( x1, h1: RootedHeap.H ) ), 
  	         Right( RootedHeap.RootQ( x2, h2: RootedHeap.H ) ) ) =>
              //当两个bootstrap堆都非空的时候
              //比较两个堆的根,较小的根作为新堆的根
              //根较大的堆作为元素插入到根较小的斜二项堆中
  	      if ( ord.lteq( x1, x2 ) ) 
  	    	Right(RootedHeap.RootQ(x1, RootedHeap.insert(ts2.right.get, h1)))
  	      else
  	    	Right(RootedHeap.RootQ(x2, RootedHeap.insert(ts1.right.get, h2)))
  	}
  	
  	override def findMin( ts: H ) = ts match {
  	  case Left( Empty( _ ) ) => 
                    throw new NoSuchElementException("min of empty heap")
  	  case Right( RootedHeap.RootQ( x, h ) ) => x
  	}
  	
  	override def deleteMin( ts: H ) = ts match {
  	  case Left( Empty( _ ) ) => 
                throw new NoSuchElementException("delete min of empty heap")
  	  case Right( RootedHeap.RootQ( x, h ) ) => 
  	    	if ( RootedHeap.isEmpty( h ) ) 
  	    	  Left( Empty( "no element left" ) )
  	    	else {
                        //先查找斜二项堆h的最小元素(y, h1)
                        //然后删除斜二项堆h的最小元素
                        //最后返回新bootstrap堆,根为y,斜二项堆为h1和h2的合并
  	    		val RootedHeap.RootQ( y, h1 ) = RootedHeap.findMin( h )
  	    		val h2 = RootedHeap.deleteMin( h )
  	    		Right( RootedHeap.RootQ( y, RootedHeap.meld( h1, h2 ) ) )
  	    	}
  	}
}

另外一种定义方法:      

我觉得这个表达更加清晰(新增2013-12-16):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
trait BootstrapSkewBinomialHeap extends Heap {
  
    trait Rooted extends Heap {
	    
	    //这样定义是为了将空的bootstrap堆和非空bootstrap堆统一起来
	    trait RootType 
	    
	    case class RootQ( x: BootstrapSkewBinomialHeap.this.A, h: H) extends RootType
	    
	    case object Empty extends RootType
	
	    override type A = RootQ
		
	    object AgeOrdering extends Ordering[RootQ] {
	        def compare( a: RootQ, b: RootQ ) = 
	            BootstrapSkewBinomialHeap.this.ord.compare( a.x, b.x )
	    }
		
	    override def ord = AgeOrdering
		
	}
	
	val RootedHeap = new Rooted with SkewBinomialHeap
  
        //这样就不用Either来表示了
	override type H = RootedHeap.RootType
	
	//这样表示空堆更加自然和可读
	override def empty = RootedHeap.Empty

	override def isEmpty( ts: H ) = ts match {
  	  case RootedHeap.Empty => true
  	  case RootedHeap.RootQ(_, _) => false
  	}
  	
  	override def insert( x: A, ts: H ): H = 
  	     meld( RootedHeap.RootQ( x, RootedHeap.empty ), ts )
  	
  	override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match {
  	  case ( RootedHeap.Empty, ts ) => ts
  	  case ( ts, RootedHeap.Empty ) => ts
  	  case ( RootedHeap.RootQ( x1, h1: RootedHeap.H ), 
  	         RootedHeap.RootQ( x2, h2: RootedHeap.H ) ) =>
  	    if ( ord.lteq( x1, x2 ) ) 
  	    	RootedHeap.RootQ(x1,RootedHeap.insert(ts2.asInstanceOf[RootedHeap.RootQ],h1))
  	    else
  	    	RootedHeap.RootQ(x2,RootedHeap.insert(ts1.asInstanceOf[RootedHeap.RootQ],h2)) 
  	}
  	
  	override def findMin( ts: H ) = ts match {
  	  case RootedHeap.Empty => 
  	       throw new NoSuchElementException("min of empty heap")
  	  case RootedHeap.RootQ( x, h ) => x
  	}
  	
  	override def deleteMin( ts: H ) = ts match {
  	  case RootedHeap.Empty => 
  	       throw new NoSuchElementException("delete min of empty heap")
  	  case RootedHeap.RootQ( x, h ) => 
  	    	if ( RootedHeap.isEmpty( h ) ) 
  	    	    RootedHeap.Empty
  	    	else {
  	    	    val RootedHeap.RootQ( y, h1 ) = RootedHeap.findMin( h )
  	    	    val h2 = RootedHeap.deleteMin( h )
  	    	    RootedHeap.RootQ( y, RootedHeap.meld( h1, h2 ) )
  	    	}
  	}
}

新的定义:

这几天又学到了scala新的技巧,觉得可以运用在bootstrap堆的定义上,

其实就是个小技巧,可以让代码更简洁(新增2013-12-21):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
trait BootstrapSkewBinomialHeap extends Heap {
  
	trait Rooted extends Heap {//。。。没有变化}
	
	val RootedHeap = new Rooted with SkewBinomialHeap  
        //import 这一句就是技巧,对比上面发现
        //之前表示继承RootType的RootQ和Empty前面都要加RootedHeap
        //现在不用了,代码更简洁可读
	import RootedHeap._
	
	override type H = RootType
	
	override def empty = Empty

	override def isEmpty( ts: H ) = ts match {
  	  case Empty => true
  	  case RootQ(_, _) => false
  	}
  	
  	override def insert( x: A, ts: H ): H = meld( RootQ( x, RootedHeap.empty ), ts )
  	
  	override def meld( ts1: H, ts2: H ) = ( ts1, ts2 ) match {
  	  case ( Empty, ts ) => ts
  	  case ( ts, Empty ) => ts
  	  case ( RootQ( x1, h1: RootedHeap.H ), RootQ( x2, h2: RootedHeap.H ) ) =>
  	    	if ( ord.lteq( x1, x2 ) ) 
  	    		RootQ( x1, RootedHeap.insert( ts2.asInstanceOf[RootQ], h1) )
  	    	else
  	    		RootQ( x2, RootedHeap.insert( ts1.asInstanceOf[RootQ], h2 ) ) 
  	}
  	
  	override def findMin( ts: H ) = ts match {
  	  case Empty => throw new NoSuchElementException("min of empty heap")
  	  case RootQ( x, h ) => x
  	}
  	
  	override def deleteMin( ts: H ) = ts match {
  	  case Empty => throw new NoSuchElementException("delete min of empty heap")
  	  case RootQ( x, h ) => 
  	    	if ( RootedHeap.isEmpty( h ) ) 
  	    	  Empty
  	    	else {
  	    		val RootQ( y, h1 ) = RootedHeap.findMin( h )
  	    		val h2 = RootedHeap.deleteMin( h )
  	    		RootQ( y, RootedHeap.meld( h1, h2 ) )
  	    	}
  	}
}

测试:

测试Int类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
object Test {

  def main(args: Array[String]): Unit = {                
                 //这里新建一个元素类型是Int的bootstrap堆
		  val heap = new BootstrapSkewBinomialHeap with IntHeap		  
                  //依次插入元素,其实认真观察,发现和传统的数据结构相比,
                  //每次操作之后原来的版本和新的版本同时存在,并不想传统的数据结构,
                  //更新操作之后,原来的版本就找不回来了。
		  val heap1 =  heap.insert(1, heap.empty)
		  val heap2 =  heap.insert(10, heap1)
		  val heap3 =  heap.insert(-1, heap2)
		  val heap4 =  heap.insert(-11, heap3)
		  val heap5 =  heap.insert(3, heap4)
		  val heap6 =  heap.insert(2, heap5)
		  
		  println(s"insert number: 1, 10, -1, -11, 3, 2")
		  
		  println(s" heap one   findMin: ${heap.findMin(heap1)}")
		  println(s" heap two   findMin: ${heap.findMin(heap2)}")
		  println(s" heap three findMin: ${heap.findMin(heap3)}")
		  println(s" heap four  findMin: ${heap.findMin(heap4)}")
		  println(s" heap five  findMin: ${heap.findMin(heap5)}")
		  println(s" heap six   findMin: ${heap.findMin(heap6)}")
		  
		  val meldheap26 = heap.meld(heap2, heap6)
		  println(s"meld heap two and six then findMin: ${heap.findMin(heap6)}")
		  
		  val heap7 = heap.deleteMin(heap6)
		  println(s"deleteMin heap six and then findMin: ${heap.findMin(heap7)}")

		  val heap8 = heap.deleteMin(heap7)
		  println(s"deleteMin heap seven and then findMin: ${heap.findMin(heap8)}")
  }

}

结果:

换String元素类型测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
object Test {

  trait StringHeap extends Heap {
	  override type A  = String
	  override def ord = scala.math.Ordering.String 
  }
  
  def main(args: Array[String]): Unit = {                 
          //元素类型是String的bootstrap堆
          val heap = new BootstrapSkewBinomialHeap with StringHeap
		  
		  val heap1 =  heap.insert("my", heap.empty)
		  val heap2 =  heap.insert("name", heap1)
		  val heap3 =  heap.insert("is", heap2)
		  val heap4 =  heap.insert("ldpe2g", heap3)
		  val heap5 =  heap.insert("hexie", heap4)
		  val heap6 =  heap.insert("fake", heap5)
		  
		  println(s"insert String: my, name, is, ldpe2g, hexie, fake")
		  
		  println(s" heap one   findMin: ${heap.findMin(heap1)}")
		  println(s" heap two   findMin: ${heap.findMin(heap2)}")
		  println(s" heap three findMin: ${heap.findMin(heap3)}")
		  println(s" heap four  findMin: ${heap.findMin(heap4)}")
		  println(s" heap five  findMin: ${heap.findMin(heap5)}")
		  println(s" heap six   findMin: ${heap.findMin(heap6)}")
		  
		  val meldheap26 = heap.meld(heap2, heap6)
		  println(s"meld heap two and six then findMin: ${heap.findMin(heap6)}")
		  
		  val heap7 = heap.deleteMin(heap6)
		  println(s"deleteMin heap six and then findMin: ${heap.findMin(heap7)}")

		  val heap8 = heap.deleteMin(heap7)
		  println(s"deleteMin heap seven and then findMin: ${heap.findMin(heap8)}")
    
  }

}

结果:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
纯函数式堆(纯函数式优先级队列)part one ----二项堆
前言: 这篇文章是基于我看过的一篇论文,主要是关于函数式数据结构,函数式堆(优先级队列), 我会以自己的理解写下来,然后论文中出现的代码将会使用scala这们语言。 论文链接:   Optimal Purely Functional Priority Queues,另外一个链接:   论文。 这里有个好网站介绍:coursera,全球在线课程,各种课程都有。 scala这们语言的一些学习资料: scala的教程:   scala turorials(文档和更高阶的教程这个网站
Ldpe2G
2018/07/09
6680
纯函数式堆(纯函数式优先级队列)part two ----斜二项堆
前言: 这篇文章是基于我看过的一篇论文,主要是关于函数式数据结构,函数式堆(优先级队列), 我会以自己的理解写下来,然后论文中出现的代码将会使用scala这们语言。 论文链接:   Optimal Purely Functional Priority Queues,另外一个链接:   论文。 正文: 紧接part one的内容,接下来进入斜二项堆。 斜二项堆(skew binomial queue):      斜二项堆支持插入操作O(1)的时间复杂度,通过借用random-access lists中的技
Ldpe2G
2018/07/09
8140
【C++】优先级队列以及仿函数
在C++中优先级队列的相关接口就是如上这些。这里的top,如果大的值优先级高,也就是大堆,top返回的就是堆里面的最大值,如果是小的数优先级高,也就是小堆,返回的就是最小值。
羚羊角
2024/12/29
950
【C++】优先级队列以及仿函数
LeetCode 题目解答—— 第 372 到 415 题
【题目】Your task is to calculate ab mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array.
四火
2022/07/19
7910
LeetCode 题目解答—— 第 372 到 415 题
函数式编程与面向对象编程[4]:Scala的类型关联Type Alias函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。
一个会写诗的程序员
2018/08/20
7830
Java基础知识点
有人说, 有些面试题很变态,个人认为其实是因为我们基础不扎实或者没有深入。本篇文章来自一位很资深的前辈对于最近java面试题目所做的总结归纳,有170道题目 ,知识面很广 ,而且这位前辈对于每个题都自己测试给出了答案 ,如果你对某个题有疑问或者不明白,可以把题目复制下来然后发表评论,大家一起探讨
小黑同学
2022/05/10
1.1K0
Java基础知识点
Spark Streaming + Canal + Kafka打造Mysql增量数据实时进行监测分析
Spark中的Spark Streaming可以用于实时流项目的开发,实时流项目的数据源除了可以来源于日志、文件、网络端口等,常常也有这种需求,那就是实时分析处理MySQL中的增量数据。
王知无-import_bigdata
2021/04/21
1.5K0
Spark Streaming + Canal + Kafka打造Mysql增量数据实时进行监测分析
数据结构与算法(4)——优先队列和堆什么是优先队列?堆和二叉堆LeetCode相关题目整理
听这个名字就能知道,优先队列也是一种队列,只不过不同的是,优先队列的出队顺序是按照优先级来的;在有些情况下,可能需要找到元素集合中的最小或者最大元素,可以利用优先队列ADT来完成操作,优先队列ADT是一种数据结构,它支持插入和删除最小值操作(返回并删除最小元素)或删除最大值操作(返回并删除最大元素);
我没有三颗心脏
2018/07/24
1.3K0
数据结构与算法(4)——优先队列和堆什么是优先队列?堆和二叉堆LeetCode相关题目整理
JAVA编程学习经验实践积累总结分享
1. 大量群发邮件:购买Edm服务,大的互联网企业是和邮箱服务商签订协议(百度,腾讯,京东,阿里,csdn)
coderlwz
2023/05/07
7880
Spark源码和调优简介 Spark Core
作者:calvinrzluo,腾讯 IEG 后台开发工程师 本文基于 Spark 2.4.4 版本的源码,试图分析其 Core 模块的部分实现原理,其中如有错误,请指正。为了简化论述,将部分细节放到了源码中作为注释,因此正文中是主要内容。 Spark Core RDD RDD(Resilient Distributed Dataset),即弹性数据集是 Spark 中的基础结构。RDD 是 distributive 的、immutable 的,可以被 persist 到磁盘或者内存中。 对 RDD
腾讯技术工程官方号
2020/02/10
1.4K0
Spark源码和调优简介 Spark Core
如何设计并实现一个线程安全的 Map ?(上篇)
Map 是一种很常见的数据结构,用于存储一些无序的键值对。在主流的编程语言中,默认就自带它的实现。C、C++ 中的 STL 就实现了 Map,JavaScript 中也有 Map,Java 中有 HashMap,Swift 和 Python 中有 Dictionary,Go 中有 Map,Objective-C 中有 NSDictionary、NSMutableDictionary。
一缕殇流化隐半边冰霜
2018/08/30
2.1K0
如何设计并实现一个线程安全的 Map ?(上篇)
大数据技术之_19_Spark学习_02_Spark Core 应用解析+ RDD 概念 + RDD 编程 + 键值对 RDD + 数据读取与保存主要方式 + RDD 编程进阶 + Spark Cor
  我们需要一个效率非常快,且能够支持迭代计算和有效数据共享的模型,Spark 应运而生。RDD 是基于工作集的工作模式,更多的是面向工作流。   但是无论是 MR 还是 RDD 都应该具有类似位置感知、容错和负载均衡等特性。
黑泽君
2019/05/10
2.5K0
大数据技术之_19_Spark学习_02_Spark Core 应用解析+ RDD 概念 + RDD 编程 + 键值对 RDD + 数据读取与保存主要方式 + RDD 编程进阶 + Spark Cor
大数据技术之_19_Spark学习_07_Spark 性能调优 + 数据倾斜调优 + 运行资源调优 + 程序开发调优 + Shuffle 调优 + GC 调优 + Spark 企业应用案例
  每一台 host 上面可以并行 N 个 worker,每一个 worker 下面可以并行 M 个 executor,task 们会被分配到 executor 上面去执行。stage 指的是一组并行运行的 task,stage 内部是不能出现 shuffle 的,因为 shuffle 就像篱笆一样阻止了并行 task 的运行,遇到 shuffle 就意味着到了 stage 的边界。   CPU 的 core 数量,每个 executor 可以占用一个或多个 core,可以通过观察 CPU 的使用率变化来了解计算资源的使用情况,例如,很常见的一种浪费是一个 executor 占用了多个 core,但是总的 CPU 使用率却不高(因为一个 executor 并不总能充分利用多核的能力),这个时候可以考虑让一个 executor 占用更少的 core,同时 worker 下面增加更多的 executor,或者一台 host 上面增加更多的 worker 来增加并行执行的 executor 的数量,从而增加 CPU 利用率。但是增加 executor 的时候需要考虑好内存消耗,因为一台机器的内存分配给越多的 executor,每个 executor 的内存就越小,以致出现过多的数据 spill over 甚至 out of memory 的情况。   partition 和 parallelism,partition 指的就是数据分片的数量,每一次 task 只能处理一个 partition 的数据,这个值太小了会导致每片数据量太大,导致内存压力,或者诸多 executor 的计算能力无法利用充分;但是如果太大了则会导致分片太多,执行效率降低。在执行 action 类型操作的时候(比如各种 reduce 操作),partition 的数量会选择 parent RDD 中最大的那一个。而 parallelism 则指的是在 RDD 进行 reduce 类操作的时候,默认返回数据的 paritition 数量(而在进行 map 类操作的时候,partition 数量通常取自 parent RDD 中较大的一个,而且也不会涉及 shuffle,因此这个 parallelism 的参数没有影响)。所以说,这两个概念密切相关,都是涉及到数据分片的,作用方式其实是统一的。通过 spark.default.parallelism 可以设置默认的分片数量,而很多 RDD 的操作都可以指定一个 partition 参数来显式控制具体的分片数量。   看这样几个例子:   (1)实践中跑的 Spark job,有的特别慢,查看 CPU 利用率很低,可以尝试减少每个 executor 占用 CPU core 的数量,增加并行的 executor 数量,同时配合增加分片,整体上增加了 CPU 的利用率,加快数据处理速度。   (2)发现某 job 很容易发生内存溢出,我们就增大分片数量,从而减少了每片数据的规模,同时还减少并行的 executor 数量,这样相同的内存资源分配给数量更少的 executor,相当于增加了每个 task 的内存分配,这样运行速度可能慢了些,但是总比 OOM 强。   (3)数据量特别少,有大量的小文件生成,就减少文件分片,没必要创建那么多 task,这种情况,如果只是最原始的 input 比较小,一般都能被注意到;但是,如果是在运算过程中,比如应用某个 reduceBy 或者某个 filter 以后,数据大量减少,这种低效情况就很少被留意到。   最后再补充一点,随着参数和配置的变化,性能的瓶颈是变化的,在分析问题的时候不要忘记。例如在每台机器上部署的 executor 数量增加的时候,性能一开始是增加的,同时也观察到 CPU 的平均使用率在增加;但是随着单台机器上的 executor 越来越多,性能下降了,因为随着 executor 的数量增加,被分配到每个 executor 的内存数量减小,在内存里直接操作的越来越少,spill over 到磁盘上的数据越来越多,自然性能就变差了。   下面给这样一个直观的例子,当前总的 cpu 利用率并不高:
黑泽君
2019/05/14
3K0
大数据技术之_19_Spark学习_07_Spark 性能调优 + 数据倾斜调优 + 运行资源调优 + 程序开发调优 + Shuffle 调优 + GC 调优 + Spark 企业应用案例
spark面试题目_面试提问的问题及答案
1.Spark master使用zookeeper进行HA的,有哪些元数据保存在Zookeeper? 答:spark通过这个参数spark.deploy.zookeeper.dir指定master元数据在zookeeper中保存的位置,包括Worker,Driver和Application以及Executors。standby节点要从zk中,获得元数据信息,恢复集群运行状态,才能对外继续提供服务,作业提交资源申请等,在恢复前是不能接受请求的。另外,Master切换需要注意2点 1)在Master切换的过程中,所有的已经在运行的程序皆正常运行!因为Spark Application在运行前就已经通过Cluster Manager获得了计算资源,所以在运行时Job本身的调度和处理和Master是没有任何关系的! 2) 在Master的切换过程中唯一的影响是不能提交新的Job:一方面不能够提交新的应用程序给集群,因为只有Active Master才能接受新的程序的提交请求;另外一方面,已经运行的程序中也不能够因为Action操作触发新的Job的提交请求; 2.Spark master HA 主从切换过程不会影响集群已有的作业运行,为什么? 答:因为程序在运行之前,已经申请过资源了,driver和Executors通讯,不需要和master进行通讯的。 3.Spark on Mesos中,什么是的粗粒度分配,什么是细粒度分配,各自的优点和缺点是什么? 答:1)粗粒度:启动时就分配好资源, 程序启动,后续具体使用就使用分配好的资源,不需要再分配资源;好处:作业特别多时,资源复用率高,适合粗粒度;不好:容易资源浪费,假如一个job有1000个task,完成了999个,还有一个没完成,那么使用粗粒度,999个资源就会闲置在那里,资源浪费。2)细粒度分配:用资源的时候分配,用完了就立即回收资源,启动会麻烦一点,启动一次分配一次,会比较麻烦。 4.如何配置spark master的HA? 1)配置zookeeper 2)修改spark_env.sh文件,spark的master参数不在指定,添加如下代码到各个master节点 export SPARK_DAEMON_JAVA_OPTS=”-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=zk01:2181,zk02:2181,zk03:2181 -Dspark.deploy.zookeeper.dir=/spark” 3) 将spark_env.sh分发到各个节点 4)找到一个master节点,执行./start-all.sh,会在这里启动主master,其他的master备节点,启动master命令: ./sbin/start-master.sh 5)提交程序的时候指定master的时候要指定三台master,例如 ./spark-shell –master spark://master01:7077,master02:7077,master03:7077 5.Apache Spark有哪些常见的稳定版本,Spark1.6.0的数字分别代表什么意思? 答:常见的大的稳定版本有Spark 1.3,Spark1.6, Spark 2.0 ,Spark1.6.0的数字含义 1)第一个数字:1 major version : 代表大版本更新,一般都会有一些 api 的变化,以及大的优化或是一些结构的改变; 2)第二个数字:6 minor version : 代表小版本更新,一般会新加 api,或者是对当前的 api 就行优化,或者是其他内容的更新,比如说 WEB UI 的更新等等; 3)第三个数字:0 patch version , 代表修复当前小版本存在的一些 bug,基本不会有任何 api 的改变和功能更新;记得有一个大神曾经说过,如果要切换 spark 版本的话,最好选 patch version 非 0 的版本,因为一般类似于 1.2.0, … 1.6.0 这样的版本是属于大更新的,有可能会有一些隐藏的 bug 或是不稳定性存在,所以最好选择 1.2.1, … 1.6.1 这样的版本。 通过版本号的解释说明,可以很容易了解到,spark2.1.1的发布时是针对大版本2.1做的一些bug修改,不会新增功能,也不会新增API,会比2.1.0版本更加稳定。 6.driver的功能是什么? 答: 1)一个Spark作业运行时包括一个Driver进程,也是作业的主进程,具有main函数,并且有SparkContext的实例,是程序的人口点;2)功能:负责向集群申请资源,向master注册信息,负责了作业的调度,,负责作业的解析、生成Stage并调度Task到E
全栈程序员站长
2022/11/16
1.8K0
Java面试笔试题大汇总(最全+详细答案)
声明:有人说, 有些面试题很变态,个人认为其实是因为我们基础不扎实或者没有深入。本篇文章来自一位很资深的前辈对于最近java面试题目所做的总结归纳,有170道题目 ,知识面很广 ,而且这位前辈对于每个题都自己测试给出了答案 ,如果你对某个题有疑问或者不明白,可以电脑端登录把题目复制下来然后发表评论,大家一起探讨,也可以电脑端登录后关注我给我发私信,我们一起进步! 以下内容来自这位前辈 2013年年底的时候,我看到了网上流传的一个叫做《Java面试题大全》的东西,认真的阅读了以后发现里面的很多题目是重复且没
汤高
2018/01/11
30.1K0
Java面试笔试题大汇总(最全+详细答案)
大数据技术之_19_Spark学习_06_Spark 源码解析 + Spark 通信架构、脚本解析、standalone 模式启动、提交流程 + Spark Shuffle 过程 + Spark 内存
上图展示了 2 个 RDD 进行 JOIN 操作,体现了 RDD 所具备的 5 个主要特性,如下所示:   • 1)一组分区   • 2)计算每一个数据分片的函数   • 3)RDD 上的一组依赖   • 4)可选,对于键值对 RDD,有一个 Partitioner(通常是 HashPartitioner)   • 5)可选,一组 Preferred location 信息(例如,HDFS 文件的 Block 所在 location 信息) 有了上述特性,能够非常好地通过 RDD 来表达分布式数据集,并作为构建 DAG 图的基础:首先抽象一个分布式计算任务的逻辑表示,最终将任务在实际的物理计算环境中进行处理执行。
黑泽君
2019/05/14
1.6K0
大数据技术之_19_Spark学习_06_Spark 源码解析 + Spark 通信架构、脚本解析、standalone 模式启动、提交流程 + Spark Shuffle 过程 + Spark 内存
Python100Days
这可能是我目前发现最好最好的Python教程了,故整理至我的博客。 原项目GitHub地址https://github.com/jackfrued/Python-100-Days
一点儿也不潇洒
2018/08/07
9.9K0
推荐阅读
相关推荐
纯函数式堆(纯函数式优先级队列)part one ----二项堆
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文