Spark实现提前中断正在运行的算子,并回到driver程序进行操作
让运行到一半的spark算子(如map,combineByKey等)在出现某些条件时可以中断运算,回到driver程序
最近实现导师交代的一个任务:大概就是利用spark实现一种快速算法,能够从多行数据中,挑选出头两个满足一个判定条件的匹配行,但是一个表中可能存在不止两个满足匹配条件的行,所以目标就是要在第一次遇到满足匹配条件的两个行时,就可以直接结束运算,以缩短运算时间。
在实现这个算法的过程中遇到一个需求:让spark算子执行到某一步时(即第一次遇到匹配行时),通过某些控制条件,让整个spark程序停止,跳出算子回到driver程序或者在那一步保存结果到文件。
在网上查了很久,找官方文档也没有找到直接能够实现的方法与接口,于是在想了很久之后用一种方法实现了:设置一个累加器(stopFlag),在driver程序中创建一个线程持续监听这个累加器的值,如果累加器的值发生了改变,则在driver中控制程序结束,在算子中,当出现需要提前结束算子运算的情况时(如第一次遇到匹配行),则改变累加器的值。通过这样一个方法实现了不用遍历完整个数据集,而提前结束算子的逻辑。
示例代码如下:
//用累加器创造控制条件
val stopFlag = sparkSession.sparkContext.longAccumulator("stopFlag")
//创建线程用于持续监听累加器状态
class Listener extends Runnable{
var flag=true
override def run(): Unit = {
var flag=true
while(flag){
this.synchronized{
//捕捉到累加器变化时,中断程序减少运算时间
if(stopFlag.value==999){
flag=false
println("提前停止程序")
//输出结果,结束程序
sparkSession.stop()
System.exit(1)
}
}
Thread.sleep(500)
}
}
}
//创建额外线程持续监听累加器状况
val e1 = new Listener
val li = new Thread(e1)
li.start()
//在算子中,通过改变累加器的值,来向driver传输运算状态
rdd1.foreach{x=>{
if(//出现中断条件){
stopFlag.add(999)
}
}
}
本文作为spark学习过程中的一个记录。