Difference between revisions of "LSL Script Efficiency/zh-Hans"

From Second Life Wiki
Jump to navigation Jump to search
m
 
(6 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Multi-lang|LSL Script Efficiency}}
{{Multi-lang|LSL Script Efficiency}}{{LSL Header{{#var:lang}}}}
<div style="float:right;">__TOC__</div>{{LSL Header}}
<div style="float:right;">__TOC__</div>


<div id="box">
<div id="box">
== LSL代码的执行效率 ==
== LSL脚本的执行效率 ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


效率是指一段特定的代码要实现某个目标需要占用资源的多少。它一般是指代码执行的速度,但不限于此。
效率是指一段特定的脚本要实现某个目标需要占用资源的多少。它一般是指脚本执行的速度,但不限于此。
以下是几点需要注意的事项,大体上按重要性排序:
以下是几点需要注意的事项,大体上按重要性排序:


* 为实现某种效果而使用大量的代码。详见“设计高效率的代码”
* 为实现某种效果而使用大量的脚本。详见“设计高效率的脚本”
* [[llSleep]] - 当代码休眠时,这个函数每帧大概要多消耗0.2到0.3毫秒,使用timers会更好。
* [[llSleep]] - 当脚本休眠时,这个函数每帧大概要多消耗 0.2 到 0.3 毫秒,使用 timers 会更好。
* 频繁使用timers(<5秒)
* 频繁使用 timers (<5秒)
* Listen - 特别是对0号频道的监听。
* Listen - 特别是对0号频道的监听。
* 频繁地改变材质(别人不得不下载它们)
* 频繁地改变纹理(别人不得不下载它们)
* 不恰当地用server/physical rotations代替omega
* 不恰当地用服务器/物理旋转代替 omega
* 非必要的事件处理函数(touch, collision, ...)
* 非必要的事件处理函数 (touch, collision, ...)
* 大量的email或IM
* 大量的 email 或 IM
* 低效的代码(如linear search)
* 低效的脚本(如线性查找)
* 使用较大的循环(轮询法)
* 使用闲置循环 (在一个循环中反复请求数据)


</div></div>
</div></div>
Line 26: Line 26:
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


一个物体中的每个无用脚本都增加每帧0.001到0.003的脚本时间耗费。脚本越少越好。
一个对象中的每个无用脚本都耗费每帧 0.001 到 0.003 的脚本时间,所以脚本越少越好。
* If you need to have a bunch of "buttons", don't put a script in each prim.  Use [[llDetectedLinkNumber]] to detect which button was touched from your main script instead. 
* If you need to change color, alpha, or texture of child prims, do not put a script in each prim.  Instead use [[llSetLinkAlpha]], [[llSetLinkColor]], [[llSetLinkTexture]], or [[llSetLinkPrimitiveParams]].
* '''Never''' put a script in each prim (of a large linkset) that listens on channel 0 (or any other channel).  This is probably the worst thing you can do for efficiency.  Unfortunately it is all too common.
* Consider using [[XyzzyText]] instead of [[XyText]].


The bottom line is, if you find yourself tempted to put a script in each prim, stop and think about how you could do it differently with less scripts. There is almost always an alternative.  It is up to you to decide whether the alternative is a viable one for your application.
* 如果你需要使用一组“按钮”,不要在每个元件中加入脚本,而是在主脚本中用[[llDetectedLinkNumber]]来侦测到底是哪个按钮被触发了。  
* 如果你需要改变子元件的颜色、透明度或材质,不要在每个元件中加入脚本,而是使用[[llSetLinkAlpha]],[[llSetLinkColor]],[[llSetLinkTexture]],或[[llSetLinkPrimitiveParams]]。
* '''永远不要'''在每个元件(特别是对于包含在较大的linkset中的)中加入脚本来监听0号频道(或任何其它的频道)。对于效率而言这也许是最糟糕的事情,不幸的是这是经常发生的。
* 应考虑[[XyzzyText]]来代替[[XyText]]。
 
最起码的,如果你发现有必要在每个元件中加入脚本,也要停下来想想是否有其它的方法用更少的脚本完成它。总会有变通的方法,这种变通在你的程序中是否可行完全取决于你。


</div></div>
</div></div>
<div id="box">
<div id="box">


== Micro-optimization ==
== 微优化 ==


There are many ways to speed up scripts, such as using ++a instead of a++, however, most of these micro optimizations might not hold true in the future.
有众多方法可以让脚本的执行速度更快,比如用++a代替a++,然而,这种优化在将来未必仍然有用。




== How Fast Does That Code Run ==
== 代码到底运行得有多快 ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


The following code will get the time for each function call in millis.
下面的代码会取得调用每个函数的时间,请到[[Talk:LSL_Script_Efficiency|讨论页]]提出修改意见。由于任何微小的改动都会影响测量的精准,请不要在经过讨论之前修改这里的代码。请确保这些代码与它的注释都与[[Efficiency Tester]]页面保持一致。
 
Please first propose changes to the [[Talk:LSL_Script_Efficiency|discussion]] tab. Please do not change the code here without discussion, as any small change could reduce the accuracy of measurements. Please note this code and its comments should exactly match the code and comments presented by the [[Efficiency Tester]] page.


Thanks to {{User|Xaviar Czervik}} for the original code, thanks to {{User|Strife Onizuka}} for tuning the code to produce more accurate measurements, and thanks to the other contributors listed in the history of this article.
感谢{{User|Xaviar Czervik}}提供原始代码,感谢{{User|Strife Onizuka}}调整了这些代码使它更加准确,也要感谢列在本文编辑历史中的所有贡献者。


<pre>
<pre>
Line 88: Line 87:
     float t2 = time();//remove the time required by the framework
     float t2 = time();//remove the time required by the framework
     float elapsed = ((t1 - t0) - (t2 - t1))/max;
     float elapsed = ((t1 - t0) - (t2 - t1))/max;
     llOwnerSay("The function in the loop took a total of " + (string)elapsed + " milliseconds.");
     llOwnerSay("The function in the loop took a total of " + (string)elapsed + "  
 
milliseconds.");
   }
   }
}
}
Line 96: Line 97:
<div id="box">
<div id="box">


== Efficiency ==
== 效率 ==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


The following data was collected using the above function in a recently deployed empty (though not private) sim, with only that one script running in a HUD attachment. 20 tests of each were run and averaged.
下面的数据是使用上面的代码在一个刚部署的(但不是私人的)模拟器上取得的, 这个代码单独运行在一个HUD附件上。测试进行了20次并取了平均值。
   ++a:    0.173780 ms    std. dev.:  0.003393 ms
   ++a:    0.173780 ms    std. dev.:  0.003393 ms
   a += 1:  0.181720 ms    std. dev.:  0.013267 ms
   a += 1:  0.181720 ms    std. dev.:  0.013267 ms
   a++:    0.243500 ms    std. dev.:  0.013816 ms
   a++:    0.243500 ms    std. dev.:  0.013816 ms
Thus a++ takes 40% longer to execute than ++a (rough estimate).


While the following data is correct, the function above was not used. A slightly less optimized version written by {{User|Xaviar Czervik}} was used. If someone could please repeat the tests with the function above.
因此a++的执行时间比++a长40%(粗略估计)。


   ++a:    0.364700 millis
下面的数据同样是正确的,只是它没有用上面的函数,它用的是一个由{{User|Xaviar Czervik}}稍作优化的版本。可能的话请大家用上面的函数重复测试。
   a += 1:  0.346900 millis
   ++a:    0.364700 毫秒
   a++:    0.413700 millis
   a += 1:  0.346900 毫秒
   a++:    0.413700 毫秒


Testing the same function in for loops:
这是用相同的函数在for循环中所做的测试:
   ++a:    0.358370 millis
   ++a:    0.358370 毫秒
   a += 1:  0.351200 millis
   a += 1:  0.351200 毫秒
   a++:    0.424600 millis
   a++:    0.424600 毫秒


[[llOwnerSay]] v. [[llSay]] v. [[llShout]] v. [[llWhisper]] (Channel 0 where applies):
[[llOwnerSay]] v. [[llSay]] v. [[llShout]] v. [[llWhisper]] (监听0号频道):
   llOwnerSay(): 4.359000 millis
   llOwnerSay(): 4.359000 毫秒
   llWhisper():  5.201000 millis
   llWhisper():  5.201000 毫秒
   llSay():      5.226000 millis
   llSay():      5.226000 毫秒
   llShout():  14.877000 millis
   llShout():  14.877000 毫秒


Different Channels ([[llSay]]() Used for all):
不同频道 (全部使用[[llSay]]()):
   -100000000: 1.226400 millis
   -100000000: 1.226400 毫秒
   -100000:    1.254300 millis
   -100000:    1.254300 毫秒
   -100:      1.296100 millis
   -100:      1.296100 毫秒
   -1:        1.292400 millis
   -1:        1.292400 毫秒
   0:          5.226000 millis
   0:          5.226000 毫秒
   1:          1.242300 millis
   1:          1.242300 毫秒
   100:        1.249100 millis
   100:        1.249100 毫秒
   100000:    1.219700 millis
   100000:    1.219700 毫秒
   100000000:  1.228700 millis
   100000000:  1.228700 毫秒


Amount of text ([[llSay]]() and Channel 1 used for all):
文本长度 ([[llSay]]() 全部使用1号频道):
<pre>
<pre>
   1 Character:    1.242300 millis
   1 字节:    1.242300 毫秒
   10 Characters:  1.309700 millis
   10 字节:  1.309700 毫秒
   100 Characters: 1.965600 millis
   100 字节: 1.965600 毫秒
</pre>
</pre>
[[Category:LSL 教程 (简体中文)]]

Latest revision as of 17:14, 3 March 2009

LSL脚本的执行效率

效率是指一段特定的脚本要实现某个目标需要占用资源的多少。它一般是指脚本执行的速度,但不限于此。 以下是几点需要注意的事项,大体上按重要性排序:

  • 为实现某种效果而使用大量的脚本。详见“设计高效率的脚本”
  • llSleep - 当脚本休眠时,这个函数每帧大概要多消耗 0.2 到 0.3 毫秒,使用 timers 会更好。
  • 频繁使用 timers (<5秒)
  • Listen - 特别是对0号频道的监听。
  • 频繁地改变纹理(别人不得不下载它们)
  • 不恰当地用服务器/物理旋转代替 omega
  • 非必要的事件处理函数 (touch, collision, ...)
  • 大量的 email 或 IM
  • 低效的脚本(如线性查找)
  • 使用闲置循环 (在一个循环中反复请求数据)

设计高效率的脚本

一个对象中的每个无用脚本都耗费每帧 0.001 到 0.003 的脚本时间,所以脚本越少越好。

  • 如果你需要使用一组“按钮”,不要在每个元件中加入脚本,而是在主脚本中用llDetectedLinkNumber来侦测到底是哪个按钮被触发了。
  • 如果你需要改变子元件的颜色、透明度或材质,不要在每个元件中加入脚本,而是使用llSetLinkAlphallSetLinkColorllSetLinkTexture,或llSetLinkPrimitiveParams
  • 永远不要在每个元件(特别是对于包含在较大的linkset中的)中加入脚本来监听0号频道(或任何其它的频道)。对于效率而言这也许是最糟糕的事情,不幸的是这是经常发生的。
  • 应考虑XyzzyText来代替XyText

最起码的,如果你发现有必要在每个元件中加入脚本,也要停下来想想是否有其它的方法用更少的脚本完成它。总会有变通的方法,这种变通在你的程序中是否可行完全取决于你。

微优化

有众多方法可以让脚本的执行速度更快,比如用++a代替a++,然而,这种优化在将来未必仍然有用。


代码到底运行得有多快

下面的代码会取得调用每个函数的时间,请到讨论页提出修改意见。由于任何微小的改动都会影响测量的精准,请不要在经过讨论之前修改这里的代码。请确保这些代码与它的注释都与Efficiency Tester页面保持一致。

感谢Xaviar Czervik提供原始代码,感谢Strife Onizuka调整了这些代码使它更加准确,也要感谢列在本文编辑历史中的所有贡献者。

//IMPORTANT: Only perform tests in an empty region.
// To reduce contamination and be sure to wearing no attachments.
// Preferably do tests in a private sim with one on it.
// Don't move while performing the test.
// There is a margin of error so run the tests multiple times to determine it.

integer time() { // count milliseconds since the day began
    string stamp = llGetTimestamp(); // "YYYY-MM-DDThh:mm:ss.ff..fZ"
    return (integer) llGetSubString(stamp, 11, 12) * 3600000 + // hh
           (integer) llGetSubString(stamp, 14, 15) * 60000 +  // mm
           llRound((float)llGetSubString(stamp, 17, -2) * 1000000.0)/1000; // ss.ff..f
}

default {
  state_entry() {
    llOwnerSay((string) llGetFreeMemory());

    //test variables
    float counter;

    //framework variables
    float i = 0;
    float j = 0;
    float max = 10000; // 2ms of work takes 20 seconds to repeat 10,000 times, plus overhead

    float t0 = time();
    do {

      //test
      counter += 1;
      
    }while (++i < max);
    float t1 = time();
    do ; while (++j < max);
    float t2 = time();//remove the time required by the framework
    float elapsed = ((t1 - t0) - (t2 - t1))/max;
    llOwnerSay("The function in the loop took a total of " + (string)elapsed + " 

milliseconds.");
  }
}

效率

下面的数据是使用上面的代码在一个刚部署的(但不是私人的)模拟器上取得的, 这个代码单独运行在一个HUD附件上。测试进行了20次并取了平均值。

  ++a:     0.173780 ms    std. dev.:  0.003393 ms
  a += 1:  0.181720 ms    std. dev.:  0.013267 ms
  a++:     0.243500 ms    std. dev.:  0.013816 ms

因此a++的执行时间比++a长40%(粗略估计)。

下面的数据同样是正确的,只是它没有用上面的函数,它用的是一个由Xaviar Czervik稍作优化的版本。可能的话请大家用上面的函数重复测试。

  ++a:     0.364700 毫秒
  a += 1:  0.346900 毫秒
  a++:     0.413700 毫秒

这是用相同的函数在for循环中所做的测试:

  ++a:     0.358370 毫秒
  a += 1:  0.351200 毫秒
  a++:     0.424600 毫秒

llOwnerSay v. llSay v. llShout v. llWhisper (监听0号频道):

  llOwnerSay(): 4.359000 毫秒
  llWhisper():  5.201000 毫秒
  llSay():      5.226000 毫秒
  llShout():   14.877000 毫秒

不同频道 (全部使用llSay()):

  -100000000: 1.226400 毫秒
  -100000:    1.254300 毫秒
  -100:       1.296100 毫秒
  -1:         1.292400 毫秒
  0:          5.226000 毫秒
  1:          1.242300 毫秒
  100:        1.249100 毫秒
  100000:     1.219700 毫秒
  100000000:  1.228700 毫秒

文本长度 (llSay() 全部使用1号频道):

   1 字节:    1.242300 毫秒
   10 字节:  1.309700 毫秒
   100 字节: 1.965600 毫秒