在AS3中编译正则表达式的高性能方法?

Naf*_*Kay 1 regex actionscript-3

我有一个非常简单的问题.在AS3中编译正则表达式的最佳方法(最高性能/最低内存使用率等)是什么?

例如,是这样的:

private var expression:RegExp = new RegExp(".*a$");

private function modify():void {
    /* uses "expression" to chop up string */
}
Run Code Online (Sandbox Code Playgroud)

比这更快:

private var expression:RegExp = /.*a$/;

private function modify():void {
    /* uses "expression" to chop up string */
}
Run Code Online (Sandbox Code Playgroud)

另外,如果我只打算使用一次,是否真的需要使表达式成为实例变量?例如,理论上,以下哪个代码块会执行得更快:

private var myRegEx:RegExp = /\n/;    

private function modify1():void {
    myString.split(/\n/);
}

private function modify2():void {
    myString.split(myRegEx);
}
Run Code Online (Sandbox Code Playgroud)

modify1()会以与modify2()相同的执行速度运行吗?我的意思是,AS3是否在modify1()中编译了一个新的RegExp实例,因为它没有绑定到实例变量?

非常感激任何的帮助 :)

bac*_*dos 5

你的测试不是很好.原因如下:

  1. getTimer测量时间,但cpu-time实际上很重要.如果在某个时刻,由于某种原因,调度程序决定不运行Flash播放器,那么在同一时间范围内你的cpu-time就会减少.这就是结果变化的原因.这是你可以使用的最好的,但如果你试图追踪几个百分点的偏差,实际上并没有多大的帮助.
  2. 偏差非常小.大约8%.其中一部分源于第1点中描述的效果.当我运行测试时,结果确实有所不同.8%可以来自任何地方.他们甚至可能只依赖于您的机器,操作系统或次要玩家版本或其他任何东西.结果只是没有足够的依赖性.另外8%的增速是不值得考虑的,除非你发现,有一个在你的字符串处理一个可怕的瓶颈,可以通过这个固定或与招RegExp小号
  3. 最值得注意的是:您衡量的差异与正则表达式无关,只与测试中的其他内容有关.

让我详细解释一下.
试试public function test7():void{}.在我的机器上,它需要大约30%-40%的其他测试.我们有一些数字:

    Running Tests
    -------------------------------
    Testing method: test1, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01716ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 901ms
    -------------------------------
    Testing method: test2, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01706ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 892ms
    -------------------------------
    Testing method: test3, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01868ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 969ms
    -------------------------------
    Testing method: test4, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01846ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 966ms
    -------------------------------
    Testing method: test5, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01696ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 890ms
    -------------------------------
    Testing method: test6, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01696ms
        Longest Iteration Time: 5ms
        Shortest Iteration Time: 0ms
        Total Test Time: 893ms
    -------------------------------
    Testing method: test7, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.00572ms
        Longest Iteration Time: 1ms
        Shortest Iteration Time: 0ms
        Total Test Time: 306ms
    -------------------------------
Run Code Online (Sandbox Code Playgroud)

但为什么?以下几件事很昂贵:

  • getTimer() 调用全局函数(以及其他类的静态方法)很慢
  • (tester[methodName] as Function).apply(); - 这很贵.动态属性访问需要创建闭包,然后转换为匿名函数,然后通过apply调用.我想不出一个更慢的方式来调用函数.
  • var tester:RegExpTester = new RegExpTester(); - 实例化很昂贵,因为它需要分配和初始化.

以下代码将更好地运行.由测得的开销test7通过因子20减小我的机器上:

    private function test(methodName:String, iterations:int = 100):void {
        output("Testing method: " + methodName + ", " + iterations + " iterations...");    
        var start:Number = getTimer();
        var tester:RegExpTester = new RegExpTester();
        var f:Function = tester[methodName];
        for (var i:uint = 0; i < iterations; i++) f();//this call to f still is slower than the direct method call would be
        var wholeTime:Number = getTimer() - start;
        output("Test Complete.");
        output("\tAverage Iteration Time: " + (wholeTime / iterations) + "ms");
        output("\tTotal Test Time: " + wholeTime + "ms");
        output("-------------------------------");
    }
Run Code Online (Sandbox Code Playgroud)

一些数字:

    Running Tests
    -------------------------------
    Testing method: test1, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01094ms
        Total Test Time: 547ms
    -------------------------------
    Testing method: test2, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01094ms
        Total Test Time: 547ms
    -------------------------------
    Testing method: test3, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01296ms
        Total Test Time: 648ms
    -------------------------------
    Testing method: test4, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01288ms
        Total Test Time: 644ms
    -------------------------------
    Testing method: test5, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01086ms
        Total Test Time: 543ms
    -------------------------------
    Testing method: test6, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.01086ms
        Total Test Time: 543ms
    -------------------------------
    Testing method: test7, 50000 iterations...
    Test Complete.
        Average Iteration Time: 0.00028ms
        Total Test Time: 14ms
    -------------------------------
Run Code Online (Sandbox Code Playgroud)

所以现在开销减少到不到1%,这使得它不显眼(尽管事实上它可以减少更多).然而,偏差现在是16%.那是两倍多.它开始看起来更清晰了.恕我直言,它仍然没有任何意义,但实际上它指的是两种最慢的方法:test3test4.

那为什么会这样?简单:两种方法都创建一个新的RegExp对象(一个使用文字,另一个使用构造函数).这消耗了我们可以测量的时差.现在差异更大,因为之前,每次迭代你创建了3个正则表达式(每次实例化时都会初始化两个实例变量RegExpTester).但现在留下的差异是创建50000个RegExp实例.其他任何事情都同样快.

如果在回答你的问题时得出结论:文字或构造s 之间没有区别RegExp.所以我担心,答案是:"只要你记住一般性能优化规则,这并不重要." 希望有所帮助.