Spark 并行范围与使用多线程提交拆分范围之间的区别?

difference between Spark parallel range versus submit splitted range using multi-thread?

假设有 10k 个简单的直接任务要完成,哪个更好?

//method 1
spark.parallize(range(1,10k)).map(taskDone)

//method 2
range(1, 10k).stream().parallel().map(spark.rdd(x).collect() /*do one using spark*/)

它们是等价的吗?或者哪个更受欢迎?

从根本上不同。

一方面

spark.parallize(range(1,10k)).map(taskDone)

这会在本地(在驱动程序节点上)创建一个包含 10k 元素的范围对象。这个范围被传送到集群的执行器节点(每个节点接收 N 个元素),并且每个工作人员将任务应用于这 N 个元素,而驱动程序(大概 - 因为在这里,需要最后一步才能真正开始计算)等待结果回来。

更具体地说:

spark.parallize(range(1,10k))

是在驱动程序上单线程运行的代码。它所做的是创建一个范围,并要求 spark 拆分它(将其发送到执行节点)

然后

.map(taskDone)

taskDone 中的代码发送给执行器,以便在触发计算后在集群允许的范围内同时应用任务。

另一方面...

range(1, 10k).stream().parallel().map(spark.rdd(x).collect() /*do one using spark*/)

这将在驱动程序上创建一个包含 10k 个元素的范围。然后将 10k 元素中的每一个并行(并行级别是单台机器的级别,驱动程序节点,与集群无关)分配给 RDD(包含单个元素),并且(大概)创建集群的 10k 个任务,每个任务处理一个元素。

第二种做事方式几乎肯定会非常低效。 Spark 旨在分布式处理(非常)大的集合,使用一种使其看起来像是在本地处理的编程模型。这是您的第一个代码示例。

你的第二个代码以相反的方式工作:它在单个“计算机”(主节点)上创建大量非常小的集合,这违背了目的:没有使用运送一个集合单个元素到计算集群 !

更具体地说:

range(1, 10k).stream().parallel().map(spark.rdd(x)

这是在驱动程序的单台计算机上串行运行的代码。它创建一个范围,将其(并行地)拆分为单个(大小 = 1)元素,并将这些单个元素中的每一个转换为该单个元素的 RDD(spark 分布式集合)。

实现的并行级别是驱动程序节点的级别。并行化的是 RDD 的创建,而不是执行要在元素上完成的工作

然后:

.collect()

你要求每个 RDD 都被执行并回收。在某种程度上,sparkSession 是线程安全和并发的,那些非常小的(1 项​​)RDD 被处理并发回。

因此,您将并行度限制为驱动程序节点(通常不是那么大)的并行度,而不是使用集群的并行度(可能很大)。

按第一种方式做。