When introducing Flask, a lightweight web framework for Python, we compared it with Rails with DB access and template inheritance. Since the result was ** Rails is faster **, which is different from the external Web Framework Benchmarks, it is an article to identify the cause and resolve it.
Since it is supposed to be used by individual PJs, I wrote and compared benchmarks specialized for each application. Results ** Rails ** was found to be ** 1.493 times faster than ** Flask ** **. Rails is really fast.
The result is different from Web Framework Benchmarks. Flask is slow because there seems to be a problem on the code side, so I will verify it.
It is a benchmark test specialized for applications.
--DB access to get 1 record and display the result as a template --Be sure to access the DB from the O / R mapper --Templates always inherit the template once using the layout file (extends in Python) --Benchmark is obtained with Apache Bench. Get the average response speed 5 times when accessing 1000 times with a degree of parallelism of 10 --DB is mysql --Invalid because the session function is not used --All environments are built locally
Server start command
#In both cases, only one thread was started by the debug command.
# Rails
rails server
# Flask
python manage.py runserver
Classification | Language ver | Web framework ver |
---|---|---|
Flask | Python 3.5.0 | 0.10.1 |
Rails | ruby 2.0.0p451 | Rails 4.2.5 |
It is a command for measuring the performance of the WEB server that comes standard with Apache, and can be executed with the ** ab ** command (abbreviation for Apache Bench).
ʻAb.exe -n
ab command
#Access 1000 times with a degree of parallelism of 10
ab -n 1000 -c 10 http://127.0.0.1:3000/
--Quote: Crisp performance test with Apache Bench
In Last Flask article, it responded with ** average 2ms ** without DB access and template inheritance. Template inheritance should be cached to zero cost, and DB access does not require 7ms. Shouldn't it be 1-2ms for DB access even if you estimate a lot? There must be some reason.
After that, as a result of print debugging and investigation, I found that DB connection pooling was disabled in sql alchemy (O / R Mapper) and fixed it.
db.py
#Before correction
engine = create_engine(db_path, encoding='utf-8')
#Revised
engine = create_engine(db_path, encoding='utf-8', pool_size=5)
#* On the bench, I wrote the code to reuse the connection by digging into ThreadLocalStorage.
After re-benchmarking with Flask's DB connection pooling enabled, Flask was the fastest on average request speed. When verifying an unfamiliar web framework, it makes sense to weigh the results of an external benchmark against the results at hand.
Classification | Language ver | Web framework ver | O/R mapper |
---|---|---|---|
Django | Python 2.7.5 | Django==1.6.4 | Django proprietary implementation |
Flask | Python 3.5.0 | 0.10.1 | SQL Alchemy |
Rails | ruby 2.0.0p451 | Rails 4.2.5 | Active Record |
For me, who writes Python at work, I'm not very attracted to Flask, which is only twice as fast as Django on an execution speed basis. The more people who work in a team, the less likely they are to get rid of their existing tested assets and move on to paying the learning costs together. However, in personal PJ, I want to reduce the server cost by even 1 yen and light my nails, so I will actively use it. Money is important.
--TechEmpower's Web Framework Benchmarks Competent --Rails is fast enough --Flask, Pyramid users should check if SQL Alchemy DB Connection Pool is enabled --Django users should make sure they have DB Connection Pool enabled. --What you can do with Rails, you can do with Flask. And vice versa
I tried to generate a comparison graph. I'll investigate if Django can't be this fast.
** revel ** in go language is ** 2.41 ** times faster than ** Flask **
-Introduction of "fastest" full-stack web framework "revel"
It's pretty fun to do each tutorial. Generating anything with the Rails rails generate
command was hard to understand because it hides what's going on inside.
Rails
book_controller.rb
class BookController < ApplicationController
def index
@msg = 'Test message';
# select
book = Book.where("id = 1").all
@book = book[0];
end
end
rb:index.html.erb
<p>
<%= @msg %><br/>
<%= @book.id %><br />
<%= @book.name %><br />
<%= @book.description %><br />
</p>
Flask
index.html
{% extends "master.html" %}
{% block title %}index{% endblock %}
{% block body %}
<h1>this is index page</h1><br />
{{ book.id }}
{{ book.title }}
{{ book.publish }}
{% endblock %}
root.py
# -*- coding: utf-8 -*-
from flask import render_template, Blueprint
#The name of the first argument is the template url_Linked with the name when calling in for
from utils.db import get_db_session
from module.book import Book
app = Blueprint("index",
__name__,
url_prefix='/<user_url_slug>')
#Url when calling in template_for('index.index')
@app.route("/")
def index():
book = get_db_session().query(Book).filter(Book.id=1).all()
return render_template('root/index.html', book=book[0])
django
index.html
{% extends "master.html" %}
{% block content %}
{{ book.id }}
{{ book.name }}
{{ book.description }}
{% endblock %}
views.py
class TestView(TemplateView):
"""
test
"""
template_name = 'index.html'
def get(self, request, *args, **kwargs):
book = Book.objects.filter(id=1).get()
response = self.render_to_response({
'book': book,
})
return response
I used Rails for the first time, and the feeling of being completely exhausted was wonderful. I didn't find the Rails ecosystem so cozy. In particular, I was relieved that the settings that were output from the two systems for production and development were well thought out and had a dead design.
--No hesitation in setting. From the beginning, the appropriate production.rb
and development.rb
were generated.
--View and associated test code generated with a single command
--The asset pipeline automatically builds both css and js
――When you touch it lightly, ActiveRecord is now an ordinary O / R mapper.
--Rake command is convenient because difficult parts are put together in one task.
――A lot of Japanese documents will come out if you go around
――We were able to build from scratch and obtain a benchmark in just 3 hours when the above factors overlapped.
--High learning cost, worth it
It seems that you can set the pool value in config / database.yml
. However, if it is set to 0, an error will occur and it will not work. It seems that DB connection pooling must be enabled in Rails.
Enabling DB connection pooling will definitely speed things up, but it has side effects. DB server load. Even if you rent the highest DB instance on AWS, if you make 50,000 connections, the CPU will stick to 100% and fly with load. A DB connection is created for each thread of the server. Assuming 8 CPUs per server, it is common to start an HTTP child process with 8-48 threads, so even if pool = 1 is set, there are 1000 servers including the timeout. And DB will fly with load.
The person in the example recipe site solved it. I think that solving most problems after a while is one of the great advantages of a web framework with many users and a strong community.
-Disable connection pooling to database with Rails (ActiveRecord)
Your next line is "Sinatra" ... (・ ㅂ ・) و
Recommended Posts