首页 > 学院 > 开发设计 > 正文

优化Ruby代码使程序运行速度提高的例子

2019-10-26 19:25:31
字体:
来源:转载
供稿:网友

这篇文章主要介绍了我是如何把ruby gem contracts.ruby速度提升10倍的。

contracts.ruby在我项目里用来添加代码合约(code contracts)到Ruby中。看起来差不多是这样的:

Contract Num, Num => Numdef add(a, b) a + bend

只要add方法被调用,参数和返回值都会被检查。

20秒

本周末,我对该库进行了测试,发现其性能非常糟:

2015410153558748.jpg (631×116)

这是在随机输入下,运行1000次以后的结果。

所以,当给一个函数加入合约功能后,运行速度明显下降(约40倍这样),对此,我进行了深入的研究。

8秒

我取得了较大的进展,当传递合约时,我调用success_callback函数,该函数是个空函数,下面是这个函数的整个定义:

def self.success_callback(data)end 

原来函数调用在Ruby中是非常昂贵的,仅删除这个调用,就节省了8秒钟:

2015410153638929.jpg (635×108)删除其它一些附件函数的调用,时间花费开始从9.84-> 9.59-> 8.01秒,该库的速度马上提升到以前的两倍了。

现在,事情变的有点复杂了。

5.93秒

这里有许多年种定义一个合约的方式:匿名(lambdas)、类 (classes)、简单旧数据(plain ol' values)等。 我有个很长的case语句,用来检测合约的类型。在此合约类型基础之上,我可以做不同的事情。通过把它改为if语句,我节约了一些时间,但每次调用这个函数时,我仍然耗费了不必要的时间在仔细检查这个判定树上面:

if contract.is_a?(Class) # check argelsif contract.is_a?(Hash) # check arg...

当定义合约和构建lambda时,对树只做一次检查:

if contract.is_a?(Class) lambda { |arg| # check arg }elsif contract.is_a?(Hash) lambda { |arg| # check arg }

然后,我将完全绕过逻辑分支,通过将参数传递给预计算的lambda来进行验证,这样就节约了1.2秒时间。

2015410153721524.jpg (654×126)

预计算一些其它的If语句,差不多又节省了1秒时间:

2015410153747882.jpg (635×111)

5.09秒

将.zip转换为.times又为我节省了1秒时间:

2015410153823207.jpg (647×112)

结果证明:

args.zip(contracts).each do |arg, contract|

上面的代码要比下面这个慢:

args.each_with_index do |arg, i|

要比下面这个更慢:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表