答案 0 :(得分:4)
最大可能的优势是共享内存,特别是处理广播对象。因为这些对象被认为是只读的,所以可以在多个线程之间共享。
在使用单个任务/执行程序的情况下,您需要为每个JVM创建一个副本,因此对于N个任务,有N个副本。对于大型物体,这可能是一个严重的开销。
可以将相同的逻辑应用于其他共享对象。
答案 1 :(得分:4)
正如已经说过的,广播变量是一回事。
另一个是并发问题。看一下这段代码:
var counter = 0
var rdd = sc.parallelize(data)
rdd.foreach(x => counter += x)
println(counter)
根据在本地执行还是在群集上部署的Spark(具有不同的JVM)执行,结果可能会有所不同。在后一种情况下,parallelize
方法在执行程序之间拆分计算。计算闭包(每个节点执行其任务所需的环境),这意味着每个执行者都会收到counter
的副本。每个执行者都看到自己的变量副本,因此计算结果为0,因为没有一个执行者引用了正确的对象。另一方面,{JVM} counter
对每个工作人员可见。
当然,有一种避免这种情况的方法-使用Acumulator
(see here)。
最后但并非最不重要的一点是,将RDD
保留在内存中(默认cache
方法存储级别为MEMORY_ONLY
),它将在单个JVM中可见。也可以通过使用OFF_HEAP
来克服(这在2.4.0中是实验性的)。更多here。