在Spark中捕获异常会减慢执行速度

时间:2018-03-28 07:09:17

标签: scala apache-spark stack-overflow tail-recursion

有一个RDD包含这样的元素:

( (n_1, n_2, r), List( (t1,t2), (t3,t4), ... )

我正在尝试执行以下操作:

def p_rec_l(k: Int, acc: Double, pvals_sum: Double, n_1: Int, n_2: Int, r: Int): Double = {
  if (k==r-1) return 1 - (pvals_sum + acc)
  return p_rec_l(k+1, acc*f(k.toDouble, n_1, n_2), pvals_sum+acc, n_1, n_2, r)
}

def f(k:Double, n_1: Int, n_2:Int): Double = (n_1-k)*(n_2-k)/((k+1)*(N-n_1-n_2+k+1))
N = 2000000
someRDD.map({
    case (key, value) => (key, {
      val n_1 = key._1; val n_2 = key._2; val r = key._3
      val p_k0 = (0 to n_2-1).iterator.map(j => 1- n_1/(N-j.toDouble)).reduceLeft(_*_)
      val pval = p_rec_l(0, p_k0, 0, n_1, n_2, r)
      value.map({
        case (t1, t2) => (t1, t2, n_1, n_2, r, pval)          
      }) 
    })
})

但是如果r非常大,则会出现堆栈溢出异常,并且整个进程崩溃。我编辑了这样的代码:

someRDD.map({
    case (key, value) => (key, {
      val n_1 = key._1; val n_2 = key._2; val r = key._3
      val p_k0 = (0 to n_2-1).iterator.map(j => 1- n_1/(N-j.toDouble)).reduceLeft(_*_)
      var pval = -1.0
      try{
        pval = p_rec_l(0, p_k0, 0, n_1, n_2, r)
      } catch{
        case e: java.lang.StackOverflowError => pval = -1
      }
      value.map({
        case (t1, t2) => (t1, t2, n_1, n_2, r, pval)          
      }) 
    })
})

在版本开始之前,该程序在大约7个小时内完成,但现在它已经工作了36个小时但尚未完成。 这个try-catch子句是否有可能减慢执行速度?如果是的话,有什么方法可以推动吗?

1 个答案:

答案 0 :(得分:0)

可能更好的解决方案不是捕获StackOverflowError,而是使用@tailrec注释标记您的函数(因为我看到它是尾递归的),所以你应该完全避免使用StackOverflowError

@tailrec def p_rec_l(k: Int, acc: Double, pvals_sum: Double, n_1: Int, n_2: Int, r: Int): Double = {
  if (k==r-1) 1 - (pvals_sum + acc)
  else p_rec_l(k+1, acc*f(k.toDouble, n_1, n_2), pvals_sum+acc, n_1, n_2, r)
}

另外,为了更好地理解你的问题,我理解你比较成功执行的执行时间没有StackOverflowError和没有try-catch,而另一个执行尝试 - catch,但是使用不会导致StackOverflowError的相同数据,所以catch本身在比较时间时不起作用?