RDD分区
RDD是弹性分布式数据集,通常RDD很大,会被分成很多个分区分别保存在不同的节点上,分区的作用:(1)增加并行度(2)减少通信开销。RDD分区原则是使得分区的个数尽量等于集群中的CPU核心(core)数目,对于不同的Spark部署模式而言(本地模式、Standalone模式、YARN模式、Mesos模式),都可以通过设置spark.default.parallelism这个参数的值,来配置默认的分区数目,一般而言:
本地模式:默认为本地机器的CPU数目,若设置了local[N],则默认为N;
Standalone或YARN:在“集群中所有CPU核心数目总和”和2二者中取较大值作为默认值;
设置分区的个数有两种方法:创建RDD时手动指定分区个数,使用reparititon方法重新设置分区个数;
创建RDD时手动指定分区个数:在调用textFile()和parallelize()方法的时候手动指定分区个数即可,语法格式如 sc.textFile(path, partitionNum),其中path参数用于指定要加载的文件的地址,partitionNum参数用于指定分区个数。
scala> val array = Array(1,2,3,4,5)
scala> val rdd = sc.parallelize(array,2) //设置两个分区
reparititon方法重新设置分区个数:通过转换操作得到新 RDD 时,直接调用 repartition 方法即可,如:
复制
scala> val data = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt",2)
scala> data.partitions.size //显示data这个RDD的分区数量
scala> val rdd = data.repartition(1) //对data这个RDD进行重新分区
scala> rdd.partitions.size
res4: Int = 1
函数式编程特性
函数式编程属于声明式编程的一种,将计算描述为数学函数的求值,但函数式编程没有准确的定义,只是一系列理念,并不需要严格准守,可以理解为函数式编程把程序看做是数学函数,输入的是自变量,输出因变量,通过表达式完成计算,当前越来越多的命令式语言支持部分的函数式编程特性。
在函数式编程中,函数作为一等公民,就是说函数的行为和普通变量没有区别,可以作为函参进行传递,也可以在函数内部声明一个函数,那么外层的函数就被称作高阶函数。
函数式编程的curry化:把接受多个参数的函数变换成接受一个单一参数的函数,返回接受余下的参数并且返回结果的新函数。
函数式编程要求所有的变量都是常量(这里所用的变量这个词并不准确,只是为了便于理解),erlang是其中的典型语言,虽然许多语言支持部分函数式编程的特性,但是并不要求变量必须是常量。这样的特性提高了编程的复杂度,但是使代码没有副作用,并且带来了很大的一个好处,那就是大大简化了并发编程。
Java中最常用的并发模式是共享内存模型,依赖于线程与锁,若代码编写不当,会发生死锁和竞争条件,并且随着线程数的增加,会占用大量的系统资源。在函数式编程中,因为都是常量,所以根本就不用考虑死锁等情况。为什么说一次赋值提高了编程的复杂度,既然所有变量都是常量,那么我们没办法更改一个变量的值,循环的意义也就不大,所以haskell与erlang中使用递归代替了循环。