本来做了一个并发抓取,以为Ruby1.9以后添加的Fiber是类似于golang那种,可以实现并发运行,可是发现效率没有提高,为了确认Fiber是不是在并发执行,于是我做了一个这样的测试代码。
首先搞一个php文件:
<?php
$i = intval(isset($_GET['i']) ? $_GET['i'] : (!empty($argv[1]) ? $argv[1] : 0));
if($i>0){
sleep(5-$i);
}
echo $i, "\n";
然后用命令行测试,确认这个php文件是不会block的(因为没有session锁,应该不会block)
time for i in {1..5}; do (curl localhost/test.php?i=$i) & if [ "$i" -eq "5" ]; then wait; fi ; done
time for i in {1..5}; do (php test.php $i) & if [ "$i" -eq "5" ]; then wait; fi ; done
这里两种方式运行时间都是4秒左右,证明,是可以并行运行。 real 0m4.019s
然后用fiber执行: real 0m10.086s 10秒左右,证明这完全是一个一个在跑的。
#!/usr/bin/env ruby
require 'open-uri';
fib = Fiber.new do
(1..5).each do |i|
Fiber.yield open("http://localhost/test.php?i=#{i}").read
end
end
Fiber.new do
5.times do
puts fib.resume
end
end.resume
结果测试发现根本不能实现并发,而且是一个一个在跑,跑完一个跑下一个,所以别在被误解了Fiber根本不能并发执行,而且还有一个更奇葩的,如果是5个Fiber.yield,在resume的时候却可以调用6次resume,这个设计真不怎么样。
后来我在 stackoverflow上找到这个 http://stackoverflow.com/questions/3066392/can-ruby-fibers-be-concurrent
看第二个回答,大概是说,Fiber只是一种 control-flow 结构,并不是用来搞并发的,他们不能并发运行,只能算是一种 Coroutine ,和并行执行不是一种东西,在ruby里,唯一能实现并发的是 Thread,那么我就奇怪为何网上有那么多人宣称可以用 Fiber 来实现并发运行?并发和协程可是不一样的。
不过也可以这样来说,Fiber是可以实现 concurrency,这个 concurrency 并不是 Parallelism,就是说,可以实现所谓的并发,但是内部却是一个一个运行的,而且并不会因为IO阻塞的时候自动调度,你需要手动调度,实际性能没有任何提升,用了只会增加代码逻辑复杂度,丝毫不能带来任何益处,同样是concurrency,golang、nodejs都可以在IO阻塞时候自动调度,所以能实现正真意义上的并发编程,但Fiber,只不过是把任务一个一个压栈,然后在一个一个等待着他们运行完毕,完全不能自由调度,真没见到有什么实质用处。
比如 这里 http://www.infoq.com/cn/news/2007/09/ruby-1-9-fibers
标题就是 :Ruby 1.9加入纤程实现轻量级并发 ,直接就是在误导新手啊.
来源:oschina
链接:https://my.oschina.net/u/170216/blog/465540