设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 4462|回复: 12
打印 上一主题 下一主题

[已经解决] 关于RPG Maker全系列Ruby脚本执行效率求解

[复制链接]

Lv1.梦旅人

梦石
0
星屑
72
在线时间
673 小时
注册时间
2006-10-3
帖子
1795

开拓者

跳转到指定楼层
1
发表于 2011-12-2 20:40:06 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
本帖最后由 熊猫 于 2011-12-2 20:40 编辑

据说VX使用了更新的Ruby版本,比XP的执行效率好得多。可是……
近来做了一个脚本性能的小测试,只针对一个方面。
首先代码是:
  1. a = Time.now
  2. e = ""
  3. f = ""
  4. for i in 0...10000000
  5. e = "aaa"
  6. f = e
  7. e = "bbb"
  8. end
  9. b = Time.now

  10. p b - a
复制代码
参赛选手:
  1. .NET 4.0
  2. RPG Maker XP
  3. RPG Maker VX
  4. RPG Maker VX Ace
复制代码
成绩嘛:
  1. .NET
  2. 0.04s
  3. Ruby:
  4. XP 3.8s
  5. VX 6.5s
  6. ACE 9.5s
复制代码
咱CPU渣,跑得慢了点……不过从时间对比上来看,结论很明显啊。
单纯字符操作一千万+1次循环来看,Ruby完败.NET,这个倒不是出乎意料。
我在意的是……XP VX VXACE一代比一代慢,而且灰常明显……

不管RGSS引擎,就Ruby来讲……版本肯定是新了的,为什么慢了呢?
VX比起XP新的Ruby脚本解释引擎到底优秀在哪里?
( ส็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ ω ส้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้【看猫君玩,我也搞一只】)

Lv1.梦旅人

梦石
0
星屑
50
在线时间
163 小时
注册时间
2011-11-12
帖子
56
13
发表于 2011-12-5 01:46:47 | 只看该作者
熊猫 发表于 2011-12-4 22:13
嗯……VX没有额外的压力还处理得那么慢,果然没有优势。应该很快会被Ace取代吧。

VX 是怎麼回事還沒想明白。

虛擬機的工作之一就是提供(編譯時、運行時的)代碼優化,這一點無論是 CLR 還是 YARV 都一樣,只是限於語言動態的天性,能達到的優化程度不同而已。就比如這段代碼,如果放到一個不是特別動態的語言中,由於用到的字符串都是常量,編譯器在編譯時就能靜態決定最終三個引用的值,在编译时就可以把有循環優化成沒有循環。然而在 Ruby 中,用戶可以利用猴子補丁隨時重定義 Range#each 這樣的方法,那麼看似是基本語言結構的 for 循環也可以在每次迭代時做一些用戶自定義的事情了,如此一來編譯器就不能確定是否可以移除循環 [1]。這些動態的信息很難被編譯器用靜態的方式分析,所以現在的動態語言虛擬機主要是靠 JIT。主樓這段 Ruby 代碼其實也沒多少「字符串處理」,整個程序的生命週期內做的就三件事:不斷的通過 "..." 字面值形式生成新的字符串對象(這是給 Ruby 堆施加壓力),不斷的把對象賦給某些局部引用變量(這是給虛擬機的內核以及棧施加壓力,但相比於其他開銷來說已是很小),回收失去引用的字符串对象(這是給 Ruby 的 GC 施加壓力)。在 .NET 中如果想測試類似的東西,那就也得讓每次迭代都生成新的對象才行,否則的話使用的字符串就有可能被字符串常量池給緩存了(也就是 string interning)。比如在 C# 中:

  1.             string s1 = "test";
  2.             string s2 = "test";
  3.             string s3 = new StringBuilder("test").ToString();
  4.             Console.WriteLine((Object)s1 == (Object)s2);        // True
  5.             Console.WriteLine((Object)s2 == (Object)s3);        // False
复制代码
可見每當使用字符串字面值時都動用了字串池進行緩存,所以在循環中賦值的時候用 StringBuilder 和字符串常量的開銷是有很大差別的。

[1] 比如,如果重定義 Range#each 為每次迭代輸出一個 1,那麼無論在任何場合下用 for i in range 都會在 for 循環原本執行的內容之餘輸出 range 長度那麼多個 1,而如果把循環移除後這個行為就被抹殺了。
回复

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
72
在线时间
673 小时
注册时间
2006-10-3
帖子
1795

开拓者

12
 楼主| 发表于 2011-12-4 22:13:52 | 只看该作者
第七水螰 发表于 2011-12-3 13:43
Ruby 1.9 加入了 Enumerator(枚舉器)的功能,默認情況下調用 #each 會在每次迭代過程中也同時進行枚舉器 ...
VX 和 XP 用的 Ruby 版本是相同的,都是 1.8.1。VX Ace 升級到了 1.9.2

嗯……VX没有额外的压力还处理得那么慢,果然没有优势。应该很快会被Ace取代吧。


其实,既然是说道了.NET我就多说一句。
.NET应该是对代码有优化的,微软这方面做得比较到位,否则执行10000000次字符处理根本不能是0.04s。

感谢这位仁兄回答,我的问题得到了解决并且学到了很多。

点评

300M内存,1.7GHZ CUP你伤的起吗。不过RUBY的速度[貌似][本来]就比[那种语言]要慢吧- -  发表于 2011-12-5 19:28
( ส็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ ω ส้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้【看猫君玩,我也搞一只】)
回复

使用道具 举报

Lv1.梦旅人

小小的百鬼夜行<

梦石
0
星屑
54
在线时间
579 小时
注册时间
2010-7-29
帖子
2682

贵宾

11
发表于 2011-12-3 14:23:55 | 只看该作者
XP :17.405
VX :46.437
外带一提,XP不用10S直接被分

点评

=。=,这是什么啊,这么长时间……  发表于 2011-12-4 22:03

评分

参与人数 1星屑 +20 收起 理由
熊猫 + 20 感谢参与测试

查看全部评分

某只PHP/HTML小白鼠→退屈の间


Cause I knew you were trouble when you walked in
So shame is on me now
I flow me to place i ve never been
till you put me down oh
Now Im lying on the cold hard ground
回复

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
163 小时
注册时间
2011-11-12
帖子
56
10
发表于 2011-12-3 13:43:45 | 只看该作者
Ruby 1.9 加入了 Enumerator(枚舉器)的功能,默認情況下調用 #each 會在每次迭代過程中也同時進行枚舉器的處理,這是 1.8 沒有的開銷。你把這個 for 循環換成 while 應該就能看到速度的提升了(這裡的 for 循環調用的是 Range#each)。當然,這段代碼最終也不會和 1.8 有太大差距,因為這段代碼測的只不過是 Ruby 的堆和 GC 性能罷了,而在這兩個方面 Ruby 1.9 並沒有多大改進。

有興趣的話可以看 1.9 源 range.c 中有關 Range#each 的部分:
  1. static VALUE
  2. range_each(VALUE range)
  3. {
  4.     VALUE beg, end;

  5.     RETURN_ENUMERATOR(range, 0, 0);

  6.     beg = RANGE_BEG(range);
  7.     end = RANGE_END(range);
  8.     ...
  9. }
复制代码
其中 RETURN_ENUMERATOR 就是額外的開銷。

VX比起XP新的Ruby脚本解释引擎到底优秀在哪里?

VX 和 XP 用的 Ruby 版本是相同的,都是 1.8.1。VX Ace 升級到了 1.9.2,這個可以在幫助菜單裏查到,或是自行在腳本中打印 RUBY_VERSION 這個常量的值。

@各种压力的猫君
Ruby是靠虚拟机运行的,.Net最后总说还有个编译器不是。

Ruby 1.9 之前的實現是純粹的抽象語法樹求值器,也就是純解釋性實現,直到 1.9 才有了虛擬機 YARV。.NET 在微軟平臺下的虛擬機是 CLR,但它和 YARV 面向的語言完全不同,YARV 主要是服務 Smalltalk 式(類 Smalltalk 面向對象模型)高度動態語言的,而 CLR 的模型更類似於 JVM。前者在執行效率上很難超過後者,但後者在動態性能上(如各種元編程能力)也別想超過前者。

评分

参与人数 5星屑 +306 收起 理由
DeathKing + 176 所以有些时候就是要找老板
⑨姐姐 + 10 谢谢前辈的说
R-零 + 20 凑不了整就……
各种压力的猫君 + 50 原来如此!受教了
熊猫 + 50 认可答案追加奖励

查看全部评分

回复

使用道具 举报

Lv5.捕梦者 (版主)

梦石
28
星屑
10170
在线时间
4673 小时
注册时间
2011-8-22
帖子
1279

开拓者

9
发表于 2011-12-3 11:06:41 | 只看该作者
builder.c
"
do sth
"
貌似可以这样用0 0?

评分

参与人数 1星屑 +20 收起 理由
熊猫 + 20 谢谢参与讨论

查看全部评分

回复

使用道具 举报

Lv2.观梦者

梦石
0
星屑
757
在线时间
1270 小时
注册时间
2011-2-14
帖子
5589
8
发表于 2011-12-3 07:46:10 | 只看该作者
貌似只是位图的处理效率比较高

评分

参与人数 1星屑 +30 收起 理由
熊猫 + 30 谢谢参与讨论

查看全部评分

回复

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
72
在线时间
673 小时
注册时间
2006-10-3
帖子
1795

开拓者

7
 楼主| 发表于 2011-12-2 23:38:47 | 只看该作者
各种压力的猫君 发表于 2011-12-2 22:52
平均值是去掉5次的最高值和最低值之后做算术平均得出的。

嗯,如果猫君在各个RM中测试的代码是一样的话,是不是可以得出这个结论:
单纯循环操作字符来看RMXP比较强。
近似总体的操作(猫君的线性插值测试,具体我也不知道是神马~)来看Ace倒是一匹黑马。
但是RMVX两项测试都处于最后。
所以RMVX脚本性能优于RMXP不成立。ACE仍有待考证。
( ส็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็็ ω ส้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้้【看猫君玩,我也搞一只】)
回复

使用道具 举报

Lv2.观梦者

(?????)

梦石
0
星屑
712
在线时间
1327 小时
注册时间
2011-7-18
帖子
3184

贵宾

6
发表于 2011-12-2 22:52:36 | 只看该作者
本帖最后由 各种压力的猫君 于 2011-12-2 22:53 编辑



平均值是去掉5次的最高值和最低值之后做算术平均得出的。
回复

使用道具 举报

Lv1.梦旅人

尽头

梦石
0
星屑
119
在线时间
278 小时
注册时间
2010-6-20
帖子
1280
5
发表于 2011-12-2 22:47:07 | 只看该作者
我猜是ruby先是给C编译再给机器运行。所以ruby的速度是慢不奇怪。

评分

参与人数 1星屑 +20 收起 理由
熊猫 + 20 谢谢参与讨论

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2025-2-17 03:33

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表