最近因为使用Ruby写一个多线程爬虫,所以积累了一点小心得:
1、多使用Benchmark测试效率,以寻找高效的实现,尤其是对于频繁执行的代码。Ruby执行的效率本身比较慢,所以代码选择很重要。
1 require 'benchmark'
2
3 n = 100000
4 Benchmark.bm { |x|
5 x.report("gsub") {
6 for i in 1..n
7 a = "abcd\nef" * 10
8 b = a.gsub(/\n/," ")
9 end
10 }
11 x.report(" tr") {
12 for i in 1..n
13 a = "a\"bcd\nef" * 10
14 b = a.tr("\n"," ")
15 end
16 }
17 }
上面执行结果:
user system total real
gsub 2.312000 0.109000 2.421000 ( 2.438000)
tr 0.656000 0.000000 0.656000 ( 0.672000)
两者效率相差近四倍。
2、关于字符串连接,尽量使用"<<",而不是"+=",因为两者效率相差巨大。
1 require 'benchmark'
2
3 Benchmark.bm { |b|
4 b.report("+= ") {
5 a = ""
6 100000.times { a += "foo" }
7 }
8 b.report("<< ") {
9 a = ""
10 100000.times { a << "foo" }
11 }
12 }
执行结果:
user system total real
+= 22.390000 9.750000 32.140000 ( 35.671000)
<< 0.094000 0.000000 0.094000 ( 0.094000)
3、注意Ruby的异常类层次:
Exception
* fatal
* NoMemoryError
* ScriptError
o LoadError
o NotImplementedError
o SyntaxError
* SignalException
o Interrupt
* StandardError
o ArgumentError
o IOError
+ EOFError
o IndexError
o LocalJumpError
o NameError
+ NoMethodError
o RangeError
+ FloatDomainError
o RegexpError
o RuntimeError
o SecurityError
o SystemCallError
o ThreadError
o TypeError
o ZeroDivisionError
* SystemExit
* SystemStackError
使用 rescue 捕捉异常时,如果没有指定捕捉的异常类型,则默认为
StandardError
。(If you write a
rescue
clause with no parameter list,
the parameter defaults to
StandardError
.——参见
Programming Ruby)
这点需要特别注意,因为我们往往习惯性假设它会捕捉所有异常。譬如Net::HTTP获取页面如果超时会抛出Timeout::Error异常,其为
Interrupt的子类,所以不能被无参的 rescue 捕获。我就在这上面栽过跟头。
4、这里有一些非常好的参考资料:
Ruby-Doc.org —— Ruby文档的权威网站
Programming Ruby —— Ruby权威的文档
Ruby Class and Library Reference —— 很方便的常见类的参考
Ruby QuickRef —— 快速索引,查各种符号和用法很方便
Ruby User's Guide —— Ruby各方面精简介绍,入门不错
PLEAC Ruby —— Ruby的Cookbook
Ruby Example Code —— 简单直观的样例代码,Ruby的HelloWorld
Ruby Essentials