Scala Fork-Join-All具有多种通用类型和1个通用工作单元

时间:2015-11-05 03:09:46

标签: scala generics reflection apache-spark scala-reflect

我正在尝试编写一个接受多个泛型类型的方法,并将一个工作单元作为参数来执行。

这个想法是工作单元是一个共同的功能,它本身就是通用的。例如,让我们说它类似于以下内容:

def loadModelRdd[T: TypeTag](sc: SparkContext): RDD[T] = {
  ...
}

loadModelRdd()将在进行一些内部处理(如加载模型信息等)后构造给定类型的RDD。

我一直在攻击的原型方法看起来像以下(非工作):

def forkAll[A : Manifest, B : Manifest](work: => RDD[_]): (RDD[A], RDD[B]) = {
  def aFuture = Future { work } // How can I notify that this work call returns type A?
  def bFuture = Future { work } // How can I notify that this work call returns type B?

  val res = for {
    a <- aFuture
    b <- bFuture
  } yield (a.asInstanceOf[A], b.asInstanceOf[B])

  Await.result(res, 10.seconds)
}

这是我正在处理的代码的缩短版本,因为我实际上正在考虑接受多达10种不同的类型。

正如您所看到的,forkAll方法的总体目标是将工作单元包装在Future中,fork-join执行每种类型的工作单元,然后将结果作为元组结果返回。消费者声明的示例如下:

val (a, b) = forkAll[ClassA, ClassB](loadModelRdd)

即我想在此时进行fork-join并等待结果,但我希望执行并行执行,然后收集回Driver(Spark Driver具体)。

问题是我不确定在构造Future {}块时如何强制forkAll中的工作单元返回的类型。没有forkAll,实现如下所示:

val resA = loadModelRdd[ClassA](sc)
val resB = loadModelRdd[ClassB](sc)
...

我正在考虑这样做有两个原因:

  1. 为与此模型匹配的任何工作单元抽象fork-join的详细信息。
  2. 此代码的一个版本,明确说明工作单元是什么,在Production中工作,并负责将长时间运行的块的执行减少近一半。我有几个可以应用此模式的执行步骤
  3. 在Scala的类型系统中,这是可能的吗?或者我应该从不同的角度看待这个问题?我已经尝试了几个实现(包括一个描述here),但我还没有找到一个适合我当前对问题的看法

    如果需要任何其他信息,请与我们联系。

    谢谢!

1 个答案:

答案 0 :(得分:0)

简短回答: Scala does not allow functions with type parameters,所以你想要的并不完全可能。

您正在尝试使用类型参数传递方法。虽然允许方法具有类型参数,但函数不允许。当您尝试传递方法时,它的作用类似于匿名函数,因此您必须指定类型。

但是,由于方法确实允许使用类型参数,因此您可以通过创建将执行fork / join的抽象类来利用此功能

abstract class ForkJoin {

  protected def work[T]: RDD[T]

  def apply[A, B]: (RDD[A], RDD[B]) = {
    // Write implementation of fork/join here
    (work[A], work[B])
  }
}

然后覆盖类型泛型work方法,以便它可以执行您想要的操作,例如调用其他预定义方法。

val forkJoin = new ForkJoin {
  override protected def work[T]: RDD[T] =
    loadModelRdd[T](sc)
}

val (intRdd, stringRdd) = forkJoin[Int, String]

查看this,了解编译和运行没有问题的原型实现。