簡體   English   中英

通用解析器類“任務不可序列化”

[英]Generic parser class `Task not serializable`

我正在嘗試構造一個類,該類接收解析器作為參數,並在每一行上使用該解析器。 下面是一個最小的示例,您可以將其粘貼到spark-shell

import scala.util.{Success,Failure,Try}
import scala.reflect.ClassTag

class Reader[T : ClassTag](makeParser: () => (String => Try[T])) {

  def read(): Seq[T] = {

    val rdd = sc.parallelize(Seq("1","2","oops","4")) mapPartitions { lines =>

      // Since making a parser can be expensive, we want to make only one per partition.
      val parser: String => Try[T] = makeParser()

      lines flatMap { line =>
        parser(line) match {
          case Success(record) => Some(record)
          case Failure(_) => None
        }
      }
    }

    rdd.collect()
  }
}

class IntParser extends (String => Try[Int]) with Serializable {
  // There could be an expensive setup operation here...
  def apply(s: String): Try[Int] = Try { s.toInt }
}

但是,當我嘗試運行類似new Reader(() => new IntParser).read() (類型檢查就很好)時,我得到了可怕的org.apache.spark.SparkException: Task not serializable與閉包有關的org.apache.spark.SparkException: Task not serializable錯誤。

為什么會有錯誤,並且有辦法重新設計以上內容以避免發生這種情況(同時使Reader保持通用)?

問題是makeParser對於class Reader是變量,並且由於您在rdd轉換中使用它,因此spark將嘗試序列化整個不可序列化的Reader類。 因此,您將獲得任務不可序列化的異常。

將Serializable添加到類Reader中將與您的代碼一起使用。 但這不是一個好習慣,因為它將序列化可能不需要的整個類變量。

通常,您可以使用函數而不是方法來避免序列化問題。 因為在scala中,函數實際上是對象,因此將被序列化。

請參閱此答案: 任務不可序列化:僅在類而非對象上調用閉包之外的函數時,java.io.NotSerializableException

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM