加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在scala combinatorparser中访问位置信息会导致性能下降

发布时间:2020-12-16 18:38:12 所属栏目:安全 来源:网络整理
导读:我在 scala中为我的解析器编写了一个新的组合子. 它是^^组合子的变体,它传递位置信息. 但访问输入元素的位置信息确实是性价比. 在我的情况下,解析一个大的例子需要大约3秒没有位置信息,它需要超过30秒. 我编写了一个可运行的示例,其中运行时在访问位置时大约
我在 scala中为我的解析器编写了一个新的组合子.

它是^^组合子的变体,它传递位置信息.
但访问输入元素的位置信息确实是性价比.

在我的情况下,解析一个大的例子需要大约3秒没有位置信息,它需要超过30秒.

我编写了一个可运行的示例,其中运行时在访问位置时大约多50%.

这是为什么?我怎样才能获得更好的运行时间?

例:

import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.Parsers
import scala.util.matching.Regex
import scala.language.implicitConversions
object FooParser extends RegexParsers with Parsers {
  var withPosInfo = false
  def b: Parser[String] = regexB("""[a-z]+""".r)  ^^@ { case (b,x) => b + " ::" + x.toString }
  def regexB(p: Regex): BParser[String] = new BParser(regex(p))
  class BParser[T](p: Parser[T]) {
    def ^^@[U](f: ((Int,Int),T) => U): Parser[U] = Parser { in =>
      val source = in.source
      val offset = in.offset
      val start = handleWhiteSpace(source,offset)
      val inwo = in.drop(start - offset)
      p(inwo) match {
        case Success(t,in1) =>
          {
            var a = 3
            var b = 4
            if(withPosInfo)
            { // takes a lot of time
              a = inwo.pos.line
              b = inwo.pos.column
            }            
            Success(f((a,b),t),in1)
          }
        case ns: NoSuccess => ns
      }
    }
  }
  def main(args: Array[String]) = {
    val r = "foo"*50000000
    var now = System.nanoTime

    parseAll(b,r) 
    var us = (System.nanoTime - now) / 1000
    println("without: %d us".format(us))
    withPosInfo = true
    now = System.nanoTime
    parseAll(b,r)
    us = (System.nanoTime - now) / 1000
    println("with   : %d us".format(us))
  }
}

输出:

without: 2952496 us

with : 4591070 us

解决方法

不幸的是,我认为你不能使用相同的方法.问题是行号最终由scala.util.parsing.input.OffsetPosition实现,它每次创建时都会构建每个换行符的列表.因此,如果它以字符串输入结束,它将在每次调用pos时解析整个事物(在您的示例中为两次).有关详细信息,请参阅 CharSequenceReader和 OffsetPosition的代码.

你可以做一件快速的事情来加快速度:

val ip = inwo.pos
a = ip.line
b = ip.column

至少避免创建两次pos.但这仍然会给你留下很多冗余的工作.我害怕真正解决你必须自己构建索引的问题,就像在OffsetPosition中一样,只需要一次,然后继续引用它.

您还可以提交错误报告/提出增强请求.这不是实现该功能的非常好的方法.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读