3.6 惰性操作

RDD的创建和转换方法都是惰性操作。当应用调用一个返回RDD的方法的时候,Spark并不会立即执行运算。比如,当你使用SparkContext的textFile方法从HDFS中读取文件时,Spark并不会马上从硬盘中读取文件。类似地,RDD转换操作(它会返回新RDD)也是惰性的。Spark会记录作用于RDD上的转换操作。

让我们考虑如下示例代码。

python polars惰性计算怎么实现的 什么是spark的惰性计算?_操作方法

 

上面三行代码看起来很快就会执行完,哪怕textFile方法读取的是一个包含了10TB数据的文件。这其中的原因是当你调用textFile方法时,它并没有真正读取文件。类似地,filter方法也没有立即遍历原RDD中的每一个元素。

Spark仅仅记录了这个RDD是怎么创建的,在它上面做转换操作会创建怎样的子RDD等信息。Spark为每一个RDD维护其各自的血统信息。在需要的时候,Spark利用这些信息创建RDD或重建RDD。

如果RDD的创建和转换都是惰性操作,那么Spark什么时候才真正读取数据和做转换操作的计算呢?下面将会解答这个问题。

触发计算的操作

当Spark应用调用操作方法或者保存RDD至存储系统的时候,RDD的转换计算才真正执行。保存RDD至存储系统也被视为一种操作,尽管它并没有向驱动程序返回值。

当Spark应用调用RDD的操作方法或者保存RDD的时候,它触发了Spark中的连锁反应。当调用操作方法的时候,Spark会尝试创建作为调用者的RDD。如果这个RDD是从文件中创建的,那么Spark会在worker节点上读取文件至内存中。如果这个RDD是通过其他RDD的转换得到的子RDD,Spark会尝试创建其父RDD。这个过程会一直持续下去,直到Spark找到根RDD。然后Spark就会真正执行这些生成RDD所必需的转换计算,从而生成作为调用者的RDD。最后,执行操作方法所需的计算,将生成的结果返回给驱动程序。

惰性转换使得Spark可以高效地执行RDD计算。直到Spark应用需要操作结果时才进行计算,Spark可以利用这一点优化RDD的操作。这使得操作流水线化,而且还避免了在网络间不必要的数据传输。