为什么headOption更快

kel*_*oti 5 queue optimization scala option

我更改了一些代码,速度提高了4.5倍。我想知道为什么。过去基本上是:

def doThing(queue: Queue[(String, String)]): Queue[(String, String)] = queue match {
  case Queue((thing, stuff), _*) => doThing(queue.tail)
  case _ => queue
}
Run Code Online (Sandbox Code Playgroud)

我将其更改为此,以极大地提高速度:

def doThing(queue: Queue[(String, String)]): Queue[(String, String)] = queue.headOption match {
  case Some((thing, stuff)) => doThing(queue.tail)
  case _ => queue
}
Run Code Online (Sandbox Code Playgroud)

_*什么和为什么与headOption相比如此昂贵?

huy*_*hjl 4

我的猜测是,在运行 scalac 后,在示例中的patmat-Xprint:all末尾,我看到调用了以下方法(为简洁起见进行了编辑):queue match { case Queue((thing, stuff), _*) => doThing(queue.tail) }

val o9 = scala.collection.immutable.Queue.unapplySeq[(String, String)](x1);
if (o9.isEmpty.unary_!)
  if (o9.get.!=(null).&&(o9.get.lengthCompare(1).>=(0)))
    {
      val p2: (String, String) = o9.get.apply(0);
      val p3: Seq[(String, String)] = o9.get.drop(1);
Run Code Online (Sandbox Code Playgroud)

因此lengthCompare以可能优化的方式比较集合的长度。对于Queue,它创建一个迭代器并迭代一次。所以这应该有点快。另一方面,drop(1)还构造一个迭代器,跳过一个元素并将其余元素添加到结果队列中,以便与集合的大小呈线性关系。

这个headOption例子更简单,它检查列表是否为空(两次比较),如果不为空则返回 a Some(head),然后将其_1_2分配给thingstuff。因此不会创建迭代器,集合的长度也不会呈线性关系。