Scala 火花蓄能器螺纹安全(蓄能器似乎已损坏)
我正在编写一个自定义的Scala 火花蓄能器螺纹安全(蓄能器似乎已损坏),scala,apache-spark,concurrency,Scala,Apache Spark,Concurrency,我正在编写一个自定义的累加器v2,希望它能够正确同步 据我所知,我已经读了一些关于SparkAccumeratorv2并发问题的帖子 1) 对累加器的写入发生在读取之前,反之亦然 2) 但从不同分区向累加器的写入不会同步 因此,累加器的add方法必须支持并发访问 这是证据: object MyAccumulator { val uniqueId: AtomicInteger = new AtomicInteger() } //Just a regular int accumulator b
累加器v2
,希望它能够正确同步
据我所知,我已经读了一些关于SparkAccumeratorv2
并发问题的帖子
1) 对累加器的写入发生在读取之前,反之亦然
2) 但从不同分区向累加器的写入不会同步
因此,累加器的add
方法必须支持并发访问
这是证据:
object MyAccumulator {
val uniqueId: AtomicInteger = new AtomicInteger()
}
//Just a regular int accumulator but with a delay inside Add method
class MyAccumulator(var w: Int = 0) extends AccumulatorV2[Int, Int] {
//log this id to prove that updates happen on the same object
val thisAccId = MyAccumulator.uniqueId.incrementAndGet()
override def isZero: Boolean = w == 0
override def copy(): AccumulatorV2[Int, Int] = new MyAccumulator(w)
override def reset(): Unit = w = 0
override def add(v: Int): Unit = {
println(s"Start adding $thisAccId " + Thread.currentThread().getId)
Thread.sleep(500)
w += v
println(s"End adding $thisAccId " + Thread.currentThread().getId)
}
override def merge(other: AccumulatorV2[Int, Int]): Unit = w += other.value
override def value: Int = w
}
object Test extends App {
val conf = new SparkConf()
conf.setMaster("local[5]")
conf.setAppName("test")
val sc = new SparkContext(conf)
val rdd = sc.parallelize(1 to 50, 10)
val acc = new MyAccumulator
sc.register(acc)
rdd.foreach(x => acc.add(x))
println(acc.value)
sc.stop()
}
输出示例:
Start adding 1 73
Start adding 1 77
Start adding 1 76
Start adding 1 74
Start adding 1 75
End adding 1 74
End adding 1 75
Start adding 1 74
End adding 1 76
End adding 1 77
End adding 1 73
Start adding 1 77
Start adding 1 76
....
....
....
1212
我们可以看到,add
方法中同时有几个线程,结果是错误的(必须是1275)
然后我查看了内置累加器的源代码(例如,org.apache.spark.util.LongAccumulator
),没有发现任何同步的痕迹。它只使用可变的var
s
它怎么能工作呢
更新:
长蓄能器确实损坏(以下代码失败):
我在spark 2.1.1上得到了正确的结果。我还将
System.identityHashCode(this)
添加到您的打印输出中,以证明对add
的同时调用发生在累加器的不同实例上。在我的例子中System.identityHashCode(myacculator.this)
总是相同的。同样在2.1.1上运行也会得到同样的结果。那么你的设置一定有问题。根据设计,蓄能器不应该是螺纹安全的。请参阅此处了解一些详细信息:我正在按原样运行示例(来自IntellijIdea)。此外,我还添加了一个打破长累加器自身的示例,我猜intellij做错了什么(这不是第一次)。尝试在spark shell中运行。
object LongAccumulatorIsBroken extends App {
val conf = new SparkConf()
conf.setMaster("local[5]")
conf.setAppName("test")
val sc = new SparkContext(conf)
val rdd = sc.parallelize((1 to 50000).map(x => 1), 1000)
val acc = new LongAccumulator
sc.register(acc)
rdd.foreach(x => acc.add(x))
val value = acc.value
println(value)
sc.stop()
assert(value == 50000, message = s"$value is not 50000")
}