Sie sind auf Seite 1von 2

Tutorial

Microseconds Matter
Performance lessons learned from hacking on Merb
By Yehuda Katz

If you want to build an app that’s blistering fast, and This clocks in at around 3 microseconds. The second
easy to extend, you can learn a few things from Merb. approach uses Ruby’s #inject:
In building Merb, we’ve heard a lot of statements like
“What are you smoking? If you picked Ruby you obvi- GHIPHWKRG DUU DUULQMHFW >@ ^_DFFL_
ously don’t care about speed!” Sadly, we’ve heard these DFFL>@FKUDFF`HQG
things from good Ruby programmers, which makes it
hard to win over people who are peeking their heads This clocks it at over 4 microseconds. The final ap-
into the Ruby world with misconceptions about what proach uses #injecting, which saves us from hav-
exactly Ruby’s strengths and weaknesses are. ing to return the accumulator from the inject block:
Why Count Microseconds? People frequently criti-
cize Merb for over-optimizing to the point of caring def method(arr) arr.injecting([])
about–gasp–microseconds. Let’s take a moment to do ^_DFFL_DFFL>@FKU`HQG
a bit of math. Merb can render approximately 2,000
requests through its critical path. By critical path I This clocks in at 6 microseconds. At this point, some-
mean the code that takes a request, routes it, instan- one usually politely stops and tells me I’m rather in-
tiates the appropriate controller, calls its action, and sane for caring about 3 microseconds. After all, a mi-
then returns the result. crosecond is a tiny amount of time.
As framework developers, we count microseconds Yet Merb bans #inject in our critical path. We also
because we’re actually dealing at that level. We only ban #returning (which costs around a microsec-
have 500 of them to render a complete request. When ond per invocation) and Symbol#to_proc (which
we reduced the time it took to run Merb’s critical path costs about 6 microseconds for a single-element Ar-
from 600 microseconds down to 500, we went from ray, and an additional microsecond for additional ele-
1,650 requests per second to 2,000 requests per sec- ments), even though the supposed elegance gains seem
ond. But what does this mean in practice? Let’s take a to outweigh the negligible performance losses.
look at a simple example: And in fact, there may be no room in your app for
this sort of aggressive number-crunching. However,
$55$< Z WKHTXLFNEURZQIR[MXPSHG contrary to popular belief, Ruby is not so slow as to
over the lazy dog) method(ARRAY).should negate optimization in the microsecond space. This
== %w(t q b f j o t l d) means that you need to know your own critical path,
and that it may in fact be true that optimizing a rarely
Let’s examine three ways to solve this problem. First, used action for efficiency over elegance is not the cor-
the simple iteration approach: rect choice. Just keep in mind that those choices are
not as obvious and lopsided as some may have you
GHIPHWKRG DUU [ >@DUUHDFK^_L_[ believe. Now that we’ve covered speed, what about
L>@FKU`[HQG modularity, another Merb hallmark.
24
the
Rubyist
Ruby is Not an API Because Ruby has powerful require the use of alias_method_chain. We don’t in-
metaprogramming facilities, many Ruby program- clude it with merb-core, and when people learn that
mers, including a large number I’d consider excellent we don’t recommend it, they’re frequently hot and
Ruby programmers, have adopted the Ruby-as-API bothered and want to prove that we’re oh so wrong.
programming model. In effect, they expect frame- Without exception, these issues can be tracked down
works, like Rails and Merb, to consider their entire to one of two sources.
codebase to be open to tinkering and modification. The first, more common reason is that the person
The poster child for this philosophy is Rails’ alias_ missed something in our public API. By recommend-
method_chain. Specifically, alias_method_ ing against the use of alias_method_chain, people
chain makes it possible to take an existing method come looking for help and are able to learn to use
and extend it with new functionality. This may seem Merb’s public API as intended instead of overriding
elegant, because it provides powerful functionality, but our methods in ways that may not be compatible with
it has some serious drawbacks. future versions of Merb.
By sending the message that any method, public or The less common, but much more interesting cause
private, is available for extending via plugins, Rails is that our public API is missing something. In other
has made it nearly impossible to do any significant words, someone is trying to achieve something with
refactoring of their growing codebase. Changing even Merb that cannot be achieved via the public API alone.
seemingly-innocuous methods can have a devastating And without exception, we have looked at those situ-
effect on any number of plugins that have signed on to ations and figured out how to enhance our public API
the alias_method_chain API approach. to support what they were trying to accomplish.
Also, using alias_method_chain as an API Spending the time to think through the interface we
makes it difficult for other developers who wish to ex- are exposing to users of the framework and plugin de-
tend methods to know how the methods might already velopers allows us to keep the number of entry-points
have been defined, leading to possible conflicts or con- into our system to a minimum, and help ensure that we
fusions that are difficult to track down. Stack traces that can refactor without breaking a lot of existing code.
involve alias_method_chain can double or triple The simplest take-away from our approach is that
in size, making it hard to track down exactly where you basically never have to monkey-patch your own
the code in question comes from. To demonstrate, the code. If you’re doing this, there is likely an issue with
critical-path stack trace of a Rails app is 17 lines above the inter-class interfaces you have exposed. While it’s
Mongrel, including a number of duplicate lines due easy to fall into the trap of looking at Ruby’s flexibility
to alias_method_chain. The Merb critical-path as a license for loose, unclear interfaces, our experience
trace, by contrast, is just 7 lines above Rack. shows that spending the time to design your interfaces
So what’s the solution, then, if using Ruby as an API pays off.
is verboten? Merb’s approach is to clearly define a lim- I Still Think You Guys Are Nuts! After reading
ited public API that is to be used by app developers, this, you might think that our approach works fine
and a slightly more expansive API to be used by plugin in framework code, but is way too aggressive for app
developers. The vast majority of Merb’s methods, how- code. We pretty much agree with that, and almost no-
ever, are considered private functionality, and extend- body on the Merb core team writes our applications
ing those methods is not supported. using the aggressive approach we use in Merb’s critical
But wait just a cotton-picking minute. Who wants path. But it’s still worth keeping in mind that Ruby
to be programming in Java or C# with “final” classes is not so slow as to make small gains irrelevant, that
and methods? As it turns out, forcing ourselves to pro- Ruby can be made to be fairly fast if it needs to be, and
gram to a public API, and forcing our non-essential that well designed interfaces are possible, even though
modules (merb-more) to follow the same Plugin API Ruby-the-language makes them strictly unnecessary.
that we expect plugin developers to use has led to ex-
tremely extensible code.
Yehuda Katz is a core team member
More than a few people have hopped into the Merb of the Merb and jQuery projects. He
IRC room with an example of a case that seemed to currently works for Engine Yard as a
Merb developer.
http://www.yehudakatz.com/

Das könnte Ihnen auch gefallen