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

Project1

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

[讨论] 【效率测试】Ruby中include方法的效率问题

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1024
在线时间
1389 小时
注册时间
2010-8-9
帖子
3471
跳转到指定楼层
1
发表于 2015-1-28 13:08:14 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 寒冷魔王 于 2015-1-28 13:18 编辑

昨天重构了SMRC,新建类Point表示点的坐标,期间运用到了include方法。发现这个版本比上次发布的版本效率要快1倍。
今天调试了半天,终于找到了原因:include方法判断的内容:数组还是类。
如下发布测试代码:
  1. class Test
  2.   def self.test(string,&block)
  3.     time = Time.new
  4.     block.call
  5.     puts string,Time.new-time
  6.   end
  7. end

  8. class Point
  9.   attr_accessor :x, :y
  10.   def initialize(x, y)
  11.     @x = x
  12.     @y = y
  13.   end
  14.   def ==(point)
  15.     return @x==point.x && @y==point.y
  16.   end
  17. end

  18. point1 = Array.new
  19. point2 = Array.new
  20. max = 10000000

  21. Test.test("Push Class Point") { max.times { |i| point1.push Point.new(i,i) } }
  22. Test.test("Push Class Array") { max.times { |i| point2.push [i,i] } }
  23. Test.test("Include Class Point") { point1.include?(Point.new(max,0)) } # 取最坏情况
  24. Test.test("Include Class Array") { point2.include?([max,0]) }
复制代码
结果
  1. Push Class Point
  2. 3.588006
  3. Push Class Array
  4. 2.277604
  5. Include Class Point
  6. 1.060802
  7. Include Class Array
  8. 2.168404
复制代码
这个测试表明,使用include方法判断数组时,效率要比判断类(在类内内建方法"==")慢得多。虽然构建对象时,数组对象的构建速度要快一些。

(注:如果想要测试,请使用控制台窗口运行,否则发生死机现象与本人无关。)

围观:@taroxd  @RyanBern  

点评

嗯对~  发表于 2015-1-28 23:08
这个明明是叫做include?方法。。。  发表于 2015-1-28 21:58
SRPG on RM 项目研发组 正式成立。目前SRPG·RMVA系统进度88.8%。SMRC Kernel 进度90%
↖(^ω^)↗热烈庆祝~SMRC Ver5.1 SRPG战棋地图移动范围生成脚本正式发布~~
-----------------------------------------------------------------------------------------
SMRC具有高性能、高兼容、定制自由、使用方便的特点。
1.性能,100移动力轻松算出,无压力;
2.兼容,RGSS1-3通吃,效率保证;
3.支持移动形状定制,支持4方位、6方位、正方形或其他任意有移动规律的形状;
4.可以充当高性能寻路来使用。
【链接点此】
-----------------------------------------------------------------------------------------
【2016/01/06更新 | 改版】RM脚本编辑器Gemini
-----------------------------------------------------------------------------------------

Lv4.逐梦者 (版主)

梦石
0
星屑
9532
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

2
发表于 2015-1-28 14:24:57 | 只看该作者
我的测试结果:

因为机子太慢我改成5000000了TAT

啥?为啥不一样?因为我改了源码。
RUBY 代码复制
  1. class Test
  2.   def self.test(string,&block)
  3.     time = Time.new
  4.     block.call
  5.     puts string,Time.new-time
  6.   end
  7. end
  8.  
  9. class Point
  10.   attr_accessor :x, :y
  11.   def initialize(x, y)
  12.     @x = x
  13.     @y = y
  14.   end
  15.   def ==(point)
  16.     return @x==point.x && @y==point.y
  17.   end
  18. end
  19.  
  20. class Array
  21.   def point_include?(point_arr)
  22.     self.each do |point|
  23.       return true if point[0] == point_arr[0] && point[1] == point_arr[1]
  24.     end
  25.     return false
  26.   end
  27. end
  28.  
  29.  
  30. point1 = Array.new
  31. point2 = Array.new
  32. max = 5000000
  33.  
  34. Test.test("Push Class Point") { max.times { |i| point1.push Point.new(i,i) } }
  35.  
  36. Test.test("Push Class Array") { max.times { |i| point2.push [i,i] } }
  37.  
  38. Test.test("Include Class Point") { point1.include?(Point.new(max,0)) } # 取最坏情况
  39.  
  40. Test.test("Include Class Array") { point2.point_include?([max,0]) }

总觉得Array#==方法太不自然了。

点评

Array也是一个对象  发表于 2015-1-28 15:44
话说Ruby真是想什么就有什么,我只是试着clone一下就成功了  发表于 2015-1-28 15:40
我用Array=Array.clone在类的内部创建了一个副本,这样就不会影响到外面了~  发表于 2015-1-28 15:38
+1,这样改来,还是Array快一点。= =不过还要袭击内部类,真是各种蛋疼。。。  发表于 2015-1-28 14:41

评分

参与人数 2星屑 +190 收起 理由
恐惧剑刃 + 150 认可答案
寒冷魔王 + 40 帅气

查看全部评分

回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1024
在线时间
1389 小时
注册时间
2010-8-9
帖子
3471
3
 楼主| 发表于 2015-1-28 14:58:10 | 只看该作者
本帖最后由 寒冷魔王 于 2015-1-28 14:59 编辑
RyanBern 发表于 2015-1-28 14:24
我的测试结果:

因为机子太慢我改成5000000了TAT


我的那段程序的三个改法:(地图100*100,移动100)

第一个是使用数组+默认include的结果
第二个是我用Point类优化的结果
第三个是用你的方法更改我的程序所得的结果

第二三个差不多,第一个差许多。。果然Ruby的Array效率低啊。。

点评

Ruby是不是用Ruby的迭代实现的include啊。。我试试。。  发表于 2015-1-28 15:01
由于不知道Array#include?和Array#==是如何实现的,所以我也不清楚为啥会这么慢  发表于 2015-1-28 14:59
SRPG on RM 项目研发组 正式成立。目前SRPG·RMVA系统进度88.8%。SMRC Kernel 进度90%
↖(^ω^)↗热烈庆祝~SMRC Ver5.1 SRPG战棋地图移动范围生成脚本正式发布~~
-----------------------------------------------------------------------------------------
SMRC具有高性能、高兼容、定制自由、使用方便的特点。
1.性能,100移动力轻松算出,无压力;
2.兼容,RGSS1-3通吃,效率保证;
3.支持移动形状定制,支持4方位、6方位、正方形或其他任意有移动规律的形状;
4.可以充当高性能寻路来使用。
【链接点此】
-----------------------------------------------------------------------------------------
【2016/01/06更新 | 改版】RM脚本编辑器Gemini
-----------------------------------------------------------------------------------------
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1024
在线时间
1389 小时
注册时间
2010-8-9
帖子
3471
4
 楼主| 发表于 2015-1-28 15:06:03 | 只看该作者
本帖最后由 寒冷魔王 于 2015-1-28 15:26 编辑
RyanBern 发表于 2015-1-28 14:24
我的测试结果:

因为机子太慢我改成5000000了TAT


RUBY 代码复制
  1. class Test
  2.   def self.test(string,&block)
  3.     time = Time.new
  4.     block.call
  5.     puts string,Time.new-time
  6.   end
  7. end
  8.  
  9. point = Array.new
  10. max = 10000000
  11.  
  12. Test.test("Push Class Array") { max.times { |i| point.push [i,i] } }
  13. Test.test("Include Class Array") { point.include?([max,0]) } # 取最坏情况
  14. Test.test("Do Class Array") { point.each { |p| break if p==[max,0] } # 迭代+判断 }
  15. Test.test("Do2 Class Array") { point.each { |p| } } # 纯迭代
  16. Test.test("Do3 Class Array") { point.each { |p| a=p;a==p } } # 赋值+判断自身引用
  17. Test.test("Each_Index Class Array")  { point.each_index { |i| } } # Each_Index迭代
  18. #Test.test("Each_Index2 Class Array") { point.each_index { |i| p==[i,i] } }  # !!卡死
  19. Test.test("For Class Array")  { for i in 0...point.size; end  } # For迭代
结果
RUBY 代码复制
  1. Push Class Array
  2. 2.076804
  3. Include Class Array
  4. 2.170404
  5. Do Class Array
  6. 3.902007
  7. Do2 Class Array
  8. 0.624001
  9. Do3 Class Array
  10. 1.113064
  11. Each_Index Class Array
  12. 0.622035
  13. For Class Array
  14. 0.641037


感觉而言,Include 和 迭代+Ruby实现的判断,差不多。
根据以上测试,include效率低下应该是Array自身的判断==问题。
Array先判断是否是自身引用,然后再判断数组元素。

总而言之,Ruby的Array类是个效率非常低的类= =

点评

所以应该是Array自身的判断==问题。Array先判断是否是自身引用,然后再判断数组元素。  发表于 2015-1-28 15:19
Test.test("Each_Index2 Class Array") { point.each_index { |i| p==[i,i] } } 这一行不要试,因为卡死了。。  发表于 2015-1-28 15:18
其中赋值需要0.1s  发表于 2015-1-28 15:17
Test.test("Do3 Class Array") { point.each { |p| a=p;a==p } } 结果是1.113064  发表于 2015-1-28 15:14
那估计是Array#==太慢了?  发表于 2015-1-28 15:11
SRPG on RM 项目研发组 正式成立。目前SRPG·RMVA系统进度88.8%。SMRC Kernel 进度90%
↖(^ω^)↗热烈庆祝~SMRC Ver5.1 SRPG战棋地图移动范围生成脚本正式发布~~
-----------------------------------------------------------------------------------------
SMRC具有高性能、高兼容、定制自由、使用方便的特点。
1.性能,100移动力轻松算出,无压力;
2.兼容,RGSS1-3通吃,效率保证;
3.支持移动形状定制,支持4方位、6方位、正方形或其他任意有移动规律的形状;
4.可以充当高性能寻路来使用。
【链接点此】
-----------------------------------------------------------------------------------------
【2016/01/06更新 | 改版】RM脚本编辑器Gemini
-----------------------------------------------------------------------------------------
回复 支持 反对

使用道具 举报

Lv3.寻梦者 (版主)

…あたしは天使なんかじゃないわ

梦石
0
星屑
2208
在线时间
4033 小时
注册时间
2010-10-4
帖子
10779

开拓者贵宾

5
发表于 2015-1-30 07:50:19 | 只看该作者
本帖最后由 taroxd 于 2015-1-30 07:56 编辑

为何不用 Hash 或者 Set?

顺便提一句,数组在算 hash 的时候也很慢。

RUBY 代码复制
  1. require 'benchmark'
  2.  
  3. time = 10_000_000
  4.  
  5. default_proc = -> h, k { h[k] = Hash.new(&default_proc) }
  6.  
  7. hash = Hash.new(&default_proc)
  8.  
  9. array_key = 1,2,3,4,5
  10.  
  11. hash[array_key] = hash[1][2][3][4][5] = 0
  12.  
  13. Benchmark.bmbm do |x|
  14.   x.report("embed key") { time.times { hash[1][2][3][4][5] } }
  15.   x.report("array key") { time.times { hash[array_key] } }
  16. end
  17.  
  18. =begin
  19. Rehearsal ---------------------------------------------
  20. embed key   1.700000   0.000000   1.700000 (  1.704098)
  21. array key  14.633000   0.000000  14.633000 ( 14.631836)
  22. ----------------------------------- total: 16.333000sec
  23.  
  24.                 user     system      total        real
  25. embed key   1.669000   0.000000   1.669000 (  1.665095)
  26. array key  14.493000   0.000000  14.493000 ( 14.530831)
  27. =end

点评

Hash在处理某些问题上没数组方便,而且看ruby源代码发现貌似Array是零散的。与其这么用不如直接C++。话说有没有连续的数组?  发表于 2015-1-30 12:41

评分

参与人数 1星屑 +150 收起 理由
恐惧剑刃 + 150 认可答案

查看全部评分

回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-21 22:10

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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