Параллелизм в Ruby: неблокирующий ввод-вывод и потоки

Я экспериментирую с параллелизмом в Ruby (1.9.3-p0) и создал очень простую задачу прокси с тяжелым вводом-выводом. Сначала я попробовал неблокирующий подход:

require 'rack'
require 'rack/fiber_pool'
require 'em-http'
require 'em-synchrony'
require 'em-synchrony/em-http'

proxy = lambda {|*|
  result = EM::Synchrony.sync EventMachine::HttpRequest.new('http://google.com').get
  [200, {}, [result.response]]
}

use Rack::FiberPool, :size => 1000
run proxy

=begin
$ thin -p 3000 -e production -R rack-synchrony.ru start
>> Thin web server (v1.3.1 codename Triple Espresso)

$ ab -c100 -n100 http://localhost:3000/
Concurrency Level:      100
Time taken for tests:   5.602 seconds
HTML transferred:       21900 bytes
Requests per second:    17.85 [#/sec] (mean)
Time per request:       5602.174 [ms] (mean)
=end

Хм, я подумал, что, должно быть, делаю что-то не так. Среднее время запроса 5,6 с для задачи, в которой мы в основном ждем ввода-вывода? Я попробовал другой:

require 'sinatra'
require 'sinatra/synchrony'
require 'em-synchrony/em-http'

get '/' do
  EM::HttpRequest.new("http://google.com").get.response
end

=begin
$ ruby sinatra-synchrony.rb -p 3000 -e production
== Sinatra/1.3.1 has taken the stage on 3000 for production with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)

$ ab -c100 -n100 http://localhost:3000/
Concurrency Level:      100
Time taken for tests:   5.476 seconds
HTML transferred:       21900 bytes
Requests per second:    18.26 [#/sec] (mean)
Time per request:       5475.756 [ms] (mean)
=end

Хм, немного лучше, но не то, что я бы назвал успехом. Наконец, я попробовал многопоточную реализацию:

require 'rack'
require 'excon'

proxy = lambda {|*|
  result = Excon.get('http://google.com')
  [200, {}, [result.body]]
}    
run proxy

=begin
$ thin -p 3000 -e production -R rack-threaded.ru --threaded --no-epoll start
>> Thin web server (v1.3.1 codename Triple Espresso)

$ ab -c100 -n100 http://localhost:3000/
Concurrency Level:      100
Time taken for tests:   2.014 seconds
HTML transferred:       21900 bytes
Requests per second:    49.65 [#/sec] (mean)
Time per request:       2014.005 [ms] (mean)
=end

Это было действительно очень удивительно. Я что-то упустил? Почему здесь так плохо работают EM? Мне нужно что-то настроить? Я пробовал различные комбинации (Unicorn, несколько конфигураций Rainbows и т. Д.), Но ни одна из них даже близко не подошла к простой, старой потоковой передаче с блокировкой ввода-вывода.

Мы приветствуем идеи, комментарии и, разумеется, предложения по улучшению реализации.

13
задан BSM 12 February 2012 в 11:29
поделиться