kubo39 / bossan

high performance asynchronous rack web server
Other
28 stars 5 forks source link

Enumerator is slow #14

Closed kubo39 closed 11 years ago

kubo39 commented 11 years ago

like this app:

lambda do |env|
  [ 200, {'Content-Type'=> 'text/plain'}, "Hello, World!".chars ]
end
  1. Since creating Objects is heavy, to enumerate response body ("Hello, World!".chars.to_enum) is slow.
  2. Enumerator#next is slow, because always sigprocmask(2) calls.
rnakano commented 11 years ago

I know response body must have #each method, but almost application use [ 'one_element_array' ] as response body. I think 'TooManyElementEnumerator'.chars as response body is not often used in the first place. It's used for ... http-streaming?

If you want to focus on streaming, I think should discuss about Enumerator performance. What do you think?

kubo39 commented 11 years ago

Ooops, this example code is not good.. it's only focus on 2nd issue(calling some Enumerator#next is slow).

In common app like this:

lambda do |env|
  [ 200, {'Content-Type'=> 'text/plain'}, ["Hello, World!"] ]
end

When 10000 clients connect to the server, creating Enumerator(response body.to_enum) is no small cost in single thread eventloop(client waits another one when calling app).

http-streaming

I didn't care about...

rnakano commented 11 years ago

Okey, I understand about to_enum performance problem.

I have a simple idea to avoid performance decrement: check response_body type. If response_body is_a String, can write to socket directly. to_enum isn't needed. If Array, can use Array#each, it isn't needed. Otherwise... I think it is needed.

Of course, must measure current performance before trying this approach. What do you think about checking type idea?

kubo39 commented 11 years ago

Unfortunately, response body itself should not be an instance of String, as this will break in Ruby 1.9 under rack specification, and the body must only yield string values(I think the yield does not only point itself in block).

rnakano commented 11 years ago

Hmm... OK, I read rack specification, I see. However, checking body type looks good to me. If body is_a Array, didn't need calling Object#to_enum. Just call Array#join. If not Array, need calling to_enum, it cannot be helped.

This approach assumes that web frameworks (sinatra, rails, ...) returns Array response body as default. If so, it makes faster.

Are you happy with this?

kubo39 commented 11 years ago

+1 for checking body type.

In my proposal

Though, I'm afraid code goes complex...

rnakano commented 11 years ago

LGTM. We should refactor code after apply this proposal.

kubo39 commented 11 years ago

Hmm...I cannot decide how judge the response body type is File or not.. I can't trust that whether response body has to_path or not.

rnakano commented 11 years ago

OK, let's discuss at #15.