Scala flatMap或过滤器哪个便宜

时间:2019-01-29 11:28:31

标签: scala flink-streaming

我想使用键控流,我想知道哪种方法在高吞吐量下更好 假设我有以下

trait A{
  val id: Int 
  def isFoo: Boolean
}
case class Foo(id: Int) extends A{
  override def isFoo = true
}
case class Bar(id: Int) extends A{
  override def isFoo = false
}
val as = List[A](Foo, Bar)
val fs: List[Foo] = as.flatMap{
  case Foo => Some(Foo)
  case _ => None
}

我可以拥有以下视频流

val src: DataStream[A] = env.fromElements(as:_*)

我有这些选择:

  1. src.filter(_.isFoo).keyBy(_.id).map(...more processing...)
  2. src.filter(_.isInstanceOf[Foo]).keyBy(_.id).map(...more processing...)//here we can remove the isFoo method
  3. src.flatMap{ case f:Foo => Some(f) case _ => None }.keyBy(_.id).map(...more processing...) 我唯一的理由 选项 3 允许我从id和特征本身中删除Bar字段,因为它将创建Foo的流,这更直接。但是,按字段过滤似乎比 mapping 轻得多,特别是在高吞吐量方面。 你怎么看 ?

1 个答案:

答案 0 :(得分:14)

简短的回答:几乎可以肯定,这无关紧要,而且浪费这些时间来担心这些特定的编写过滤操作的最快方式。 ...more processing...部分几乎肯定会成为您应用程序中的瓶颈,您应该编写最清楚,最容易维护的过滤器版本。

稍微长一点的答案:即使这是某种奇怪的情况,其中这些选项中的一个明显优于其他选项,但实际上会影响应用程序的性能,您最好还是为自己编写基准测试而不是让Stack Overflow上的陌生人推测您的用例。

如果您真的要让Stack Overflow上的一个陌生人推测您的用例,我想说的一件事是,flatMap-进入Option可能不是这里的最佳选择,因为它会导致很多不必要的分配。这是一些替代实现的超级快速基准(使用Vector而不是Flink,因此要花点时间看一下结果)

import org.openjdk.jmh.annotations._

@State(Scope.Thread) class FilterBenchmark {
  val values: Vector[A] = (0 to 100).map {
    case i if i % 2 == 0 => Foo(i)
    case i => Bar(i)
  }.toVector

  @Benchmark def withIsFoo: Vector[A] = values.filter(_.isFoo)

  @Benchmark def withIsInstanceOf: Vector[A] = values.filter(_.isInstanceOf[Foo])

  @Benchmark def withFlatMap: Vector[A] = values.flatMap {
    case f @ Foo(_) => Some(f)
    case _ => None
  }

  @Benchmark def withFlatMapTypeMatch: Vector[A] = values.flatMap {
    case f: Foo => Some(f)
    case _ => None
  }

  @Benchmark def withCollect: Vector[A] = values.collect {
    case f @ Foo(_) => f
  }

  @Benchmark def withCollectTypeMatch: Vector[A] = values.collect {
    case f: Foo => f
  }
}

还有一些结果(关于2.12.8):

Benchmark                              Mode  Cnt        Score      Error  Units
FilterBenchmark.withCollect           thrpt   10  1359035.689 ± 2749.815  ops/s
FilterBenchmark.withCollectTypeMatch  thrpt   10  1361227.743 ± 2337.850  ops/s
FilterBenchmark.withFlatMap           thrpt   10   113074.826 ±  288.107  ops/s
FilterBenchmark.withFlatMapTypeMatch  thrpt   10   113188.419 ±  262.826  ops/s
FilterBenchmark.withIsFoo             thrpt   10  1254404.326 ± 3997.759  ops/s
FilterBenchmark.withIsInstanceOf      thrpt   10  1257725.670 ± 6115.773  ops/s

这个故事的寓意(在我看来)是flatMap偏离了一个数量级,而且显然很糟糕,但是其他选择之间没有足够的差异来使绩效与决策相关。