Back
Jan 22, 2017

Django vs Rails Performance

When choosing a framework to work with, it’s important to pay attention to performance. Young developers often end up doing django vs ruby on rails performance comparison.

This article is aimed for beginners, who are trying to choose the path to follow.

Contestants overview

Django

django_zW6WQ5I.png

Django is a web framework, first released in 2005. It was created to speed-up development of news websites, but evolved since then to a general purpose framework. You could’ve heard about some applications built on Django: Instagram, Bitbucket, Pinterest. As of January 2017, there are 1350 contributors to django on github.

Known for having «batteries included», Django provides built in ORM (and db migrations facilities), Admin UI, Authentication, Session management and other tools.

Core architectural principles on Django are heavily influenced by core principles of python - «explicit is better than implicit», «readability matters». The code is easy to write, easy to read and it’s always obvious how things will work when you run it.

Ruby on Rails

Ruby_On_Rails_Logo.svg.png

Ruby on Rails (RoR) was released in 2008. It was created in 37 signals to power their projects. RoR quickly gained traction and became even more popular than Django (even though was release later). RoR powers some popular websites, for example: AirBnB, Basecamp, Github, Fiverr. As of January 2017, there are 3224 contributors to Rails on github.

Just like Django, RoR provides all the base tools a developer might need to build a database driven application.

RoR follows "convention over configuration» principle, which means that you have to write less code than in Django, for example, but it’s not always immediately obvious why things work the way we work and how to modify it.

Rails vs Django comparison table

This table shows the state of rails vs django in 2017, at the time of writing this article.

 RailsDjango
Created in20082005
Github stars  
Average salary (Middle engineer)$88 544$86 801
Upwork jobs (at the time of writing article)512281
Configuration principleConvention over configurationExplicit is better than implicit
PatternModel View ControllerModel Template View
ModelsRuby on Rails has a generic ORM that allows managing database operations and migrations in Ruby. The same code works on all supported database backends. Model definition is spread across multiple files: 1. Model file, which defines business logic and validation rules 2. Migrations files, which contain definitions of incremental changes to database structure 3. Schema file, which contains a reference to current database structureDjango's ORM is similar in terms of features, but the code is organized differently: 1. Model file contains business logic, database structure and validation rules. 2. Migrations files are generated automatically as model file is updated and contain incremental db changes.
Templates<%= link_to "Show", book %><a href="{% url book %}">Show</a>
RoutingBy default Rails routes URLs to controller methods. For example POST request to /geocoder will route to create action of Geocoders controller. This behaviour can be modified with configuration file.Django requires each endpoint to be explicitly defined in python code. Each endpoint is defined as url(r'^articles/([0-9]{4})/$', views.year_archive)
JavascriptRails has built in static compilation pipeline that use coffeescript by default.Django serves static files as they are by default. Popular third-party applications add compilation and compression options.

Web framework performance

When I just started learning web development, it seemed obvious to me that raw language speed and framework optimization level are the most important parts to website performance, I even tried switching to Haskell just because it’s «fast». Now, 10 years later, it seems pretty obvious to me that framework and language speed just don’t matter in overall application performance and success.

Just by looking at the overview above we can see since Bitbucket is based on Django and Github is based on Rails and both of them are equally fast, then probably you can take any framework and build a high-loaded site that is fast enough. Still, let’s try to understand why framework speed doesn’t matter, what actually matters and what to use for your first application.

What impacts application performance

Let’s try to follow request’s lifecycle and specify what tools are involved in the process.

Request path

Load balancer

High loaded application will probably have multiple servers. Load balancer is the tool that will route the request to a needed backend. One of the most popular examples is HAProxy. SSL decryption can be also performed at this step.

Web accelerator

Accelerators are used to compress and cache responses and then quickly serve responses from cache. Most of requests will be returned here from cache, blazingly fast. Popular web accelerator is Varnish.

Web server

Nginx most probably, will serve static files and route dynamic requests to underlying application server. Note that nginx is capable to doing load balancer’s and web accelerator’s job to some extent, so it might be enough for you to just configure nginx correctly.

Application server

Application server converts http request to an object that our web framework will understand. For example, Unicorn for Rails, Gunicorn for Django.

The framework

Now at last we are running our code. In order to generate a response, our framework will have to do following: authenticate user make requests to database to pull information for all part of the page process returned data and render html

In reality, multiple levels of our application level cache kick in. Only if cache is empty on all levels, we’ll go to the database.

Cache

Memcached or Redis. Our application will try to serve user’s page from cache first. If it’s not available - it will pull page fragments from cache. For fragments that are not in cache, it will get cached database responses and render that particular fragment of html.

Database

Almost all of the websites and applications are database-driven. Waiting for database to fulfill query will take significant part of entire response time, so choosing database wisely and making queries correctly will speed-up response significantly.

Framework impact

It looks like if cache is not empty, ruby or python won’t even have to run. If it has to run, it only has to run for the fragment of the page, which is not in cache. When running, part of that time will be just waiting for the database response. Framework’s speed impact is not that important for the overall response time.

Architecture impact

When there is nothing in cache and application has to make all the db queries and render everything, it takes up to 2 seconds (including all the db queries).

Fully cached response is 10-20ms. Partially cached response will take 200ms

Optimizing database structure and queries can reduce waiting time by 90%.

As you can see, architectural decisions can change response time drastically.

Raw speed!

Ok, fine, ruby/python will run for just a fraction of total response time. Let’s measure speed difference between python and ruby during that running time - that’s exactly when raw language speed really shines.

As of January 2017, based on results from benchmarks game (http://benchmarksgame.alioth.debian.org/u64q/ruby.html), on average Python is slower than Ruby by 0.7%

TaskPython 3 (sec)Ruby (sec)
binary-trees126.0758.72
spectral-norm180.01141.49
n-body836.27723.69
pidigits3.413.14
fasta113.03108.36
reverse-complement2.934.03
k-nucleotide72.35101.95
fannkuch-redux501.72710.58
mandelbrot250.62463.95
regex-redux14.8728.80

At this point you can imagine how catastrophic for your application’s performance it would be to choose a «slower» framework.

Very funny

It might have been a little bit too long joke, but hopefully I’ve made my point - when choosing between RoR and Django, forget about speed. It’s more important how fast you can learn, how easy it is to find a job, does language matches your way of thoughts.

These frameworks while similar, have different philosophy, which is easy to notice when you start using them. Just spend a month playing with each of them and go with the one that was easier. Really. Choosing the easier way is not cheating in this case.

Subscribe for the news and updates

More thoughts
Jul 27, 2022Technology
Forge Viewer: Our Experience with an Unusual Project

Once we received an interesting task from a client. They needed to allow their users to upload a 3D model of the building and show it in a timelapse video from the construction site.

Jun 1, 2018Technology
Site search organization: basic concepts

Now it's time to get acquainted with Elasticsearch. This NoSQL database is used to store logs, analyze information and - most importantly - search.

Mar 12, 2017Technology
Creating a chat with Django Channels

Nowadays, when every second large company has developed its own instant messenger, in the era of iMessages, Slack, Hipchat, Messager, Google Allo, Zulip and others, I will tell you how to keep up with the trend and write your own chat, using django-channels 0.17.3, django 1.10.x, python 3.5.x.

Mar 3, 2017Technology
Flask vs Django. Which Is Better for Your Web App?

There are two most popular web frameworks in Python. There is the Django with lots of intelligent defaults and the Flask micro framework with complete freedom in the choice of modules. Let’s see, what django vs flask is in 2017.

Oct 11, 2010Technology
Char search in Emacs as in Vim

In VIM there is a command for char search: f. After first use it can be repeated with ;. I like to navigate in line with it. You see that you need to go to bracket in a middle of a line - you press f( and one-two ; and you are there. There's no such command in Emacs, so I had to write my own. I've managed even to implement repetition with ;.

Feb 18, 2010Technology
Absolute urls in models

Everybody knows about permalink, but it's usually used only in get_absolute_url. I prefer to use it for all related model urls.class Event(models.Model):# ...@models.permalinkdef edit_url(self):return ('event_edit', (self.pk, ))And then in template:<a href="{{ event.edit_url }}">Редактировать событие</a>