Sto giocando con la concorrenza in Ruby (1.9.3-p0) e ho creato un'attività proxy proxy I/O molto semplice. Per prima cosa ho provato l'approccio non bloccante:Concorrenza di Ruby: I/O non bloccante vs thread
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
Hmm, ho pensato che dovevo fare qualcosa di sbagliato. Un tempo medio di richiesta di 5,6 secondi per un'attività in cui ci aspettiamo principalmente I/O? Ne ho provato un altro:
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
Hmm, un po 'meglio, ma non quello che definirei un successo. Infine, ho provato un'implementazione con thread:
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
Questo è stato davvero, davvero sorprendente. Mi sto perdendo qualcosa qui? Perché l'EM si sta comportando così male qui? C'è qualche messa a punto che devo fare? Ho provato varie combinazioni (unicorno, diverse configurazioni di arcobaleni, ecc.), Ma nessuna di esse si avvicinava nemmeno al semplice, vecchio threading di I/O-blocking.
Idee, commenti e - ovviamente - suggerimenti per migliori implementazioni sono i benvenuti.
Non si dovrebbe utilizzare un server remoto per i test, la latenza può variare. Dovresti riprovare il test asincrono con meno fibre, con 20 fibre ottengo 300ms/request contro 1s/request con 1000 fibre usando la tua esatta linea ab. Il server threadato utilizza il pool di thread di eventmachine predefinito, che è 20 thread per impostazione predefinita. – Schmurfy
Non sono sicuro, l'impostazione della dimensione del pool di fibre su 20 diminuisce effettivamente le prestazioni sul mio box. – BSM
Forse non 20 ma 1000 è veramente alto, ho provato con un server locale quindi il tempo di risposta era veramente basso. – Schmurfy