Spark平行范围和使用多线程提交分裂范围之间的差异?

kxeu7u2r  于 2021-07-14  发布在  Spark
关注(0)|答案(1)|浏览(304)

假设有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*/)

它们是等价的吗?或者哪一个是首选?

ckx4rj1h

ckx4rj1h1#

这是根本不同的。

一方面

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

这将在本地(在驱动程序节点上)创建一个包含10k元素的范围对象。这个范围被传送到集群的executor节点(每个接收n个元素),每个worker将任务应用到这n个元素,而驱动程序(可能是因为这里需要最后一步来真正开始计算)等待返回结果。
更具体地说:

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

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

.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)

这是在一台计算机(驱动程序)上串行运行的代码。它创建一个范围,将其(平行地)拆分为单个(size=1)元素,并将这些单个元素中的每个元素转换为该单个元素的rdd(spark分布式集合)。
实现的并行级别是驱动程序节点的并行级别。并行化的是RDD的创建,而不是对元素执行工作
然后:

.collect()

您要求执行并收回每个rdd。只要sparksession是线程安全的和并发的,那么这些非常小的(1项)rdd就会被处理并发回。
因此,您将并行性限制为驱动程序节点的并行性(通常没有那么大),而不是使用集群的并行性(可能非常大)。
用第一种方法。

相关问题