如前所述,广播变量是一件事。
另一个问题是并发性。看一下这段代码:
var counter = 0
var rdd = sc.parallelize(data)
rdd.foreach(x => counter += x)
println(counter)
parallelize
方法将计算分配给执行器。闭包(每个节点执行任务所需的环境)被计算,这意味着每个执行器都会收到counter
的副本。每个执行器都只能看到自己的变量副本,因此计算结果为0,因为没有一个执行器引用正确的对象。另一方面,在同一个JVM中,counter
对于每个工作进程都是可见的。Acumulator
(请参阅这里)。RDD
时(默认cache
方法的存储级别为MEMORY_ONLY
),它将在单个JVM中可见。这也可以通过使用OFF_HEAP
来解决(在2.4.0中尝试性实现)。更多信息请点击这里。最大的优势是共享内存,特别是处理广播对象。因为这些对象被认为是只读的,所以可以在多个线程之间共享。
在使用单个任务/执行程序的情况下,您需要为每个 JVM 复制一份,因此对于 N 个任务,有 N 个副本。对于大型对象,这可能是一个严重的开销。
相同的逻辑也适用于其他共享对象。