【问题标题】:Catching exception in Spark slows the execution在 Spark 中捕获异常会减慢执行速度
【发布时间】:2018-03-28 07:09:16
【问题描述】:

有一个 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 子句减慢了执行速度?如果是的话,有什么办法可以改善吗?

【问题讨论】:

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


    【解决方案1】:

    可能更好的解决方案是不捕获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的情况下执行的执行时间,以及另一个使用try-catch的执行时间,但是相同的数据不会导致StackOverflowError,所以catch 本身在您比较时间时不起作用?

    【讨论】:

    • 哦,我想,如果我正在编写尾递归函数,scala 本身就知道它是尾递归的,并且在没有那个标记的情况下进行了某种优化。会试试的,谢谢。
    • 我第一次遇到stackoverflow时,我像这样限制了r:val r = math.min(1500, key._3) - 因为那个时候它是无关紧要的,我只是想知道spark是否可以处理我的数据并计算一些东西。那个时候根本没有 try-cause 子句。现在我使用相同的数据并想知道哪个三元组 (n_1, n_2, r) 导致 stackoverflow(我将它们标记为 -1)
    • 不知道您的数据,但建议在每次迭代中增加 k 后立即将 k==r-1 更改为 k>=r-1,因此如果起始值为 k 会更安全大于r-1
    • 关于注释:没有找到任何官方文档的链接,但这个答案可能有助于理解为什么需要注释:stackoverflow.com/a/35013414/546520
    • 哦,我明白了.. 好吧,我希望执行将在 3-4 小时内结束,我会尽力按照你说的做。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    相关资源
    最近更新 更多