[0.2]从Scala语言层面体验Spark的计算魅力

参考

Collections
Stream API
Memoization技术详解

场景

Spark RDD相当于一个分布式的scala集合,而Spark本身是用scala写的。本文尝试以集合元素scala.collection.immutable.Stream的使用为例,从scala语言层面内置的延迟计算与Memoization体验Spark强大的计算能力!

  • 关于延迟计算
    延迟计算能避免计算中间结果的产生,在一些计算中间过程很复杂或者很漫长的程序中,最能体现延迟计算的功力。scala中以 lazy关键字修饰的实体都具有延迟计算的特性。

  • 关于memoization
    memoization是一种可以缓存之前运算结果的技术,这样我们就不需要重新计算那些已经计算过的结果。

  • 认识Stream类
    本文以scala.collection.immutable.Stream类使用,通过实验来体验lazy与memoization的魅力。一句话介绍Stream:“Stream implements lazy lists where elements are only evaluated when they are needed.” ,简单来说就相当于 lazy 版的scala.collection.immutable.List .

这篇文章的编写纯属意外:学习Stream类的操作时发现滴!哈哈!

实验

Stream初探

Stream的创建:

scala> val strm = 1#::2#::Stream.empty
strm: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> (1 to 100).toStream.map(i=> i*3+7).filter(i=> (i%10)==0).sum
res6: Int = 1450

scala> 

以打印‘斐波那契数列’前7项为例,用两种方式实现,进一步认识Stream:
- def 版实现

scala> def fibs(a:BigInt,b:BigInt):Stream[BigInt]=a#::fibs(b,a+b)
fibs: (a: BigInt, b: BigInt)Stream[BigInt]

scala> fibs(0,1) take 7 foreach println
0
1
1
2
3
5
8
scala> 
  • val 版实现(好神奇的实现方式啊-目前还未完全理解)
scala> val fibs:Stream[BigInt]=BigInt(0)#::BigInt(1)#::fibs.zip(fibs.tail).map(n=>n._1 +n._2)
fibs: Stream[BigInt] = Stream(0, ?)

scala> fibs(7)
res4: BigInt = 13

scala> fibs take 7 foreach println
0
1
1
2
3
5
8
scala> 
延迟计算

“The class ” scala.collection.immutable.Stream 相当于 lazy版的scala.collection.immutable.List。这里以Stream的使用为例,加以说明lazy的魅力!:

scala> Range(1,50000000).filter(_%2==0)(1)
java.lang.OutOfMemoryError: GC overhead limit exceeded
scala> Stream.range(1,50000000).filter(_%2==0)(1)
res44: Int = 4 //150000000内第二个能被2整除的整数

语句:Range(1,50000000).filter(_%2==0)(1)的执行直接导致了OOM!而语句:Stream.range(1,50000000).filter(_%2==0)(1)则正确计算了结果!?因为Stream.range(1,50000000)并没有把50000000内所有的整数都列出来:
scala> Stream.range(1,50000000)
res3: scala.collection.immutable.Stream[Int] = Stream(1, ?)

而语句:Stream.range(1,50000000).filter(_%2==0)也只执行了第一小步:
scala> Stream.range(1,50000000).filter(_%2==0)
res5: scala.collection.immutable.Stream[Int] = Stream(2, ?)

memoization

memoization是一种可以缓存之前运算结果的技术,这样我们就不需要重新计算那些已经计算过的结果。Mr.Snail猜想Stream内部就使用了memoization技术,来提高迭代计算的速度。 这里以求第十二个斐波那契数为例,加以说明!

 scala> val fibs:Stream[BigInt]=BigInt(0)#::BigInt(1)#::fibs.zip(fibs.tail).map(n=>{println("Adding %d and %d".format(n._1,n._2));n._1+n._2})
fibs: Stream[BigInt] = Stream(0, ?)

scala> fibs(5)
Adding 0 and 1
Adding 1 and 1
Adding 1 and 2
Adding 2 and 3
res9: BigInt = 5

scala> fibs(10)
Adding 3 and 5
Adding 5 and 8
Adding 8 and 13
Adding 13 and 21
Adding 21 and 34
res10: BigInt = 55

scala> fibs(12)
Adding 34 and 55
Adding 55 and 89
res11: BigInt = 144

这里由于前面计算过 第10个斐波那契数,计算第12个直接在前面计算的基础上(使用Memoization技术缓存了之前运算结果),而不是再从头开始计算,所以效率极高!

总结

scala中引入了函数式编程的一些精髓:lazy、momoization等,这使其在处理一些计算场景,eg、迭代计算,具有很高的效率 -大数据计算框架Spark在很大程度上得意于scala语言本身的优良特性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值