Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> you really need to throw fast hardware at it for good performance.

That's where — non syntetic benchmark, anecdotal real-world use — Python rips Ruby apart. I cringe every time I wait for "bundle exec {rails console|rails server|rake|cap}". At every point in development, tests and production, ruby execution feels sluggish. Our routine Python dance on my 4 years old Core 2 Duo laptop runs circles around our Ruby stuff on my desktop i7-2400.

2.0 brought Ruby into decent land, but there's so much more to do. Future developments look interesting but I fear about the performance impact of new features (such as refinements).

I'm definitely keeping an eye on Topaz.



Topaz won't help for the case you describe.

The big problem with bundle exec (or Ruby startup times in general), is the ludicrous amount filesystem access because of searching through a ridiculous large number of files for each "require". E.g. if you have a ton of gem's installed, most "require" calls will look for the files you require relative to the root of every gem....

Much more extensive use of require_relative, and fewer search paths can fix that entirely.

Try an "strace 2>&1 -e last64,stat64,lstat,stat bundle exec [yourcommand] | less" and be prepared to be shocked at the waste.

(EDIT: This of course assumes you have strace; on most Linux distro's that's just a package install away - I don't know about OS X, and I've got no idea how to make dtrace do the same)


> I don't know about OS X

DTrace, eg.

   $ sudo dtruss -d -f script/rails server
you can also attach to a PID. If you are a developer on OS X it is good to know DTrace and what it is capable of. There are a lot of default scripts installed in OS X and you can write your own (if you have ever run iosnoop or execsnoop then you have already used DTrace scripts), see:

http://dtrace.org/blogs/brendan/2011/10/10/top-10-dtrace-scr...

http://hints.macworld.com/article.php?story=2007103112182371...

https://wikis.oracle.com/display/DTrace/Introduction


Thanks. I don't actually run much stuff on OS X - I use it as my work desktop, but all my "real work" is done via ssh to Linux boxes, so the OS X box is rarely running more than a browser, iTerm 2 and Thunderbird, all maximized. I only "see" OS X when something crashes....

EDIT: Completely unrelated, I just noticed who you are. We met in Mike's house when I came over for the launch of Edgeio. And I just realized how long ago that is.


require is way way faster in Ruby 2.0 typically bundle exec rails c will drop from 8 seconds to 4 just by upgrading the vm.

optimising this is not an impossible problem its just going to take time, its far from a trivial one.


It is fairly trivial if you're willing to acknowledge the real problem:

You can't pretend to not know about paths.

You can make the current case faster by optimizing this and that, but it boils down to reducing the number of stat calls, and the ways to do that are:

- Minimize the number of paths in the $LOAD_PATH. Ideally there should be one path there, but that might not be practical.

- require_relative everything when you know where it is.

As a bonus you get substantial less risk of breakage because of accidental filename clashes (yes, I've had filename clashes happen several times).

Now, this isn't quick, because it'd mean making people used to require 'gem-name/file' and have gem/bundle ensure that the default load path contains a symlink to the real current include path for every gem, but this doesn't even need a single interpreter change.

The problem here is not the Ruby implementations, but the gem ecosystem: This only becomes difficult if one wants the interpreter to automagically find files you've dropped all over the filesystem.


The biggest problem here is RubyGems which uses "load the specification for every gem you have installed"-approach. 300 gems installed = 300 files read at startup.

See also https://github.com/judofyr/quickgem for a monkey-patch that speeds startup time up to 4x.


300 files is nothing. I just strace'd an app I'm playing with that does 145,000 stat calls on startup.... It's in the process of being rewritten to do require_relative whenever possible. As for the gems, it'll probably end up with a hack to "precompile" a list of absolute paths after installation...


Another option is to build an index of the various parts of $LOAD_PATH. I monkeypatched (JRuby) to do this at runtime (that is, re-index every launch), and I saw a modest speed up in Rails boot time. If there were a standard way to build a semi-permanent index (updated by 'gem install', etc.), I'd expect the index to give even further gains. Of course, this is more invasive than your suggestions.

https://gist.github.com/pmahoney/3996724


I thought installing an SSD would speed up development on my local system in Rails 3 - it barely changed a thing.

It does make things like tests etc run way, way faster though.


Yeah, that's at least in part because of the stat()/lstat()-blowup.

After the first run most of the stat data will be cached in-memory anyway, but tens of thousands of unnecessary system calls hurts even with the actual data in memory...


For our use even assembly does not "rip Ruby apart.", looking at our 2 most common pages, topic list page and topic page, 30-50% of the time is still spent in SQL. Ruby 2.0 bring decent launch times to Rails (important for dev) due to the fixes falcon committed. Overall, the execution engine itself is pretty sweet and we have incredible visibility into the inner workings with flame graphs http://samsaffron.com/archive/2013/03/19/flame-graphs-in-rub... .

There is plenty of optimisation work left to do, but the vast majority of the issues we encounter can be addresses in either the application or libraries.

Sure, Google Go is much faster, no arguing there. Python and PyPy oth would be ballpark similar to Ruby 2.0 these days from benches I have seen.


>> 30-50% of the time is still spent in SQL

This. Ruby may be slow compared to compiled languages, but after working on Rails apps where it takes 30 seconds to run the tests, I was delighted to develop a gem using TDD. My gem has 100+ tests, and the suite starts and finishes in less than a second.

Our apps' tests suites are slow mainly because of database access, secondarily because of Rails, with Ruby itself being the smallest factor.



er, Python and PyPy are not in the same ballpark, so I'm not sure what you're talking about.


do you have any real world demos / benches etc that back you up here?


Let me google that for you http://speed.pypy.org


Just as a note: by default any modern rails app is going to call Bundler.require, so you only need to use bundle exec if e.g. your system rake is a different version or your system rails is not 3+. I've heard claims that this can have non-trivial performance effects.


If you're a Ruby developer, do yourself a favour and buy a SSD drive. It makes a huuuuuge difference !


Fixed it: "If you're a developer, do yourself a favour and buy a SSD drive. It makes a huuuuuge difference !"


Yep. I went from Rails development on an underpowered netbook (no SSD), to a 2012 Macbook Air. The difference is staggering.


Rails is the biggest offender in terms of startup speed, which I've noticed much more since I started playing with Padrino. But you're right; there's still a lot that could be done to improve speed.


You never need to run `bundle exec rails x`, just run `rails x`. Rails specifically does a lot of work so that you don't have to. For more: http://blog.wyeworks.com/2011/12/27/bundle-exec-rails-execut...


I agree completely with your anecdotal experience. It has been my experience as well.

However, I'm quite sure that the speed difference we've observed here is not due to the language implementations at the interpreter level. The two languages are similar in performance in that respect (Python being maybe incrementally faster, but not enough to notice most of the time). The faster speed noticed in this anecdote has got to be almost entirely due to the superior efficiency of the code in the tools we're using. Bundle is just slow basically.


You're talking about startup time, which is bad in this case because of the overhead Rubygems introduces by adding loads of directories to the require load path. Pre-rubygems, everything lived in a traditional $PREFIX/lib/ruby/{,site-ruby/}$VERSION/ directory just like Perl and Python, and startup times were much more comparable.

Atwood is talking about general runtime performance, and comparing it with the fast, mature JITed VMs that drive CLR languages. Python (and indeed other languages in its class) compare just as badly there.


Ironically, CRuby 2.0 has a much better GC, so it should perform much better than CPython.


It's somewhat a wash against Python 3.3 in benches I've run but that's still a big step. Python, Perl and Ruby are broadly in the same zone now.


Ruby 2.0 has a real GC that doesn't touch all pages, so it allows efficient fork.


the big pain at the moment with the MRI GC is that it stops the world, on Discourse we see a 50-60ms stall every few requests. Can totally be mitigated with unicorn and oobgc (we will move to this), still a PITA.


Check out Crystal.


I'm assuming you mean this language[1]. Crystal is a new language that uses Ruby syntax and compiles to C using LLVM. Pretty cool looking actually.

[1]https://github.com/manastech/crystal/wiki/Introduction


Yes I meant that language, glad you find it interesting


Are you using bundle exec instead of binstubs because you don't know about binstubs, or because you like things going slow?


Enough with the developer snark. You don't need to mock somebody just because they don't know about every tool in existence.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: