Ruby的Fiber根本不是用来做并发的~

[亡魂溺海] 提交于 2019-12-05 04:30:55

本来做了一个并发抓取,以为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加入纤程实现轻量级并发 ,直接就是在误导新手啊.


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!