在Spark中,我们使用广播变量使每台机器只读变量的副本。我们通常在闭包之外创建一个广播变量(例如闭包所需的查找表)以提高性能。
我们还有一个名为mapPartitions的spark转换运算符,它试图实现相同的功能(使用共享变量来提高性能)。例如,在mapPartitions中,我们可以为每个分区共享数据库连接。
那么这两者有什么区别?我们可以互换地使用它来共享变量吗?
答案 0 :(得分:4)
broadcast
用于将对象发送到每个工作节点。该对象将在该节点上的所有分区之间共享(并且对于集群中的每个节点,值/即对象都是相同的)。广播的目标是在工作节点上的许多不同任务/分区中使用相同数据时节省网络成本。
mapPartitions
是RDD上可用的方法,其工作方式与map
类似,仅适用于分区。是的,您可以定义新对象,例如jdbc连接,然后对每个分区都是唯一的。但是,您不能在不同的分区之间共享它,更不用说在不同的节点之间共享它。
答案 1 :(得分:3)
虽然KrisP提供的答案突出了所有重要的差异,但我认为值得注意的是mapPartitions
只是高级转换背后的低级构建块,而不是实现共享状态的方法。
虽然mapPartitions
可用于使共享喜欢的状态显式,但技术上不共享(其生命周期仅限于mapPartitions
闭包),并且还有其他方法可以实现它。特别是,在闭包内引用的变量在分区内共享。为了说明让我们与单身人士玩一点:
object DummySharedState {
var i = 0L
def get(x: Any) = {
i += 1L
i
}
}
sc.parallelize(1 to 100, 1).map(DummySharedState.get).max
// res3: Long = 100
sc.parallelize(1 to 100, 2).map(DummySharedState.get).max
// res4: Long = 50
sc.parallelize(1 to 100, 50).map(DummySharedState.get).max
// res5: Long = 2
和PySpark中的类似事情:
单件模块dummy_shared_state.py
:
i = 0
def get(x):
global i
i += 1
return i
主脚本:
from pyspark import SparkConf, SparkContext
import dummy_shared_state
master = "spark://..."
conf = (SparkConf()
.setMaster(master)
.set("spark.python.worker.reuse", "false"))
sc.addPyFile("dummy_shared_state.py")
sc.parallelize(range(100), 1).map(dummy_shared_state.get).max()
## 100
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 50
请注意,spark.python.worker.reuse
选项设置为false。如果你保留默认值,你实际上会看到类似的东西:
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 50
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 100
sc.parallelize(range(100), 2).map(dummy_shared_state.get).max()
## 150
在一天结束时,你必须区分三种不同的东西:
除此之外,还有一些与持久性解释器的使用相关的Python特定陷阱。
在变量生命周期中,map
(filter
或其他转换)与mapPartitions
之间仍然存在实际差异。