Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Python, Ruby và Golang:So sánh ứng dụng dịch vụ web

Sau khi so sánh gần đây về Python, Ruby và Golang cho một ứng dụng dòng lệnh, tôi đã quyết định sử dụng cùng một mẫu để so sánh việc xây dựng một dịch vụ web đơn giản. Tôi đã chọn Flask (Python), Sinatra (Ruby) và Martini (Golang) để so sánh này. Có, có nhiều tùy chọn khác cho thư viện ứng dụng web ở mỗi ngôn ngữ nhưng tôi cảm thấy ba tùy chọn này rất phù hợp để so sánh.


Tổng quan về Thư viện

Đây là so sánh cấp cao của các thư viện của Stackshare.


Bình (Python)

Flask là một khuôn khổ vi mô cho Python dựa trên Werkzeug, Jinja2 và những mục đích tốt.

Đối với các ứng dụng rất đơn giản, chẳng hạn như ứng dụng được hiển thị trong bản trình diễn này, Flask là một lựa chọn tuyệt vời. Ứng dụng Flask cơ bản chỉ có 7 dòng mã (LOC) trong một tệp nguồn Python duy nhất. Điểm hấp dẫn của Flask so với các thư viện web Python khác (chẳng hạn như Django hoặc Pyramid) là bạn có thể bắt đầu với quy mô nhỏ và xây dựng lên một ứng dụng phức tạp hơn nếu cần.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()


Sinatra (Ruby)

Sinatra là một DSL để nhanh chóng tạo các ứng dụng web trong Ruby với nỗ lực tối thiểu.

Cũng giống như Flask, Sinatra rất tuyệt vời cho các ứng dụng đơn giản. Ứng dụng Sinatra cơ bản chỉ có 4 LOC trong một tệp nguồn Ruby duy nhất. Sinatra được sử dụng thay vì các thư viện như Ruby on Rails vì lý do tương tự như Flask - bạn có thể bắt đầu nhỏ và mở rộng ứng dụng nếu cần.

require 'sinatra'

get '/hi' do
  "Hello World!"
end


Martini (Golang)

Martini là một gói mạnh mẽ để viết nhanh các ứng dụng / dịch vụ web mô-đun trong Golang.

Martini đi kèm với một số pin nhiều hơn cả Sinatra và Flask nhưng vẫn rất nhẹ khi bắt đầu - chỉ 9 LOC cho ứng dụng cơ bản. Martini đã vấp phải một số chỉ trích của cộng đồng Golang nhưng vẫn là một trong những dự án Github được đánh giá cao nhất so với bất kỳ khuôn khổ web Golang nào. Tác giả của Martini đã trực tiếp đáp trả những lời chỉ trích tại đây. Một số khung công tác khác bao gồm Revel, Gin và thậm chí cả thư viện net / http tích hợp sẵn.

package main

import "github.com/go-martini/martini"

func main() {
  m := martini.Classic()
  m.Get("/", func() string {
    return "Hello world!"
  })
  m.Run()
}

Với những kiến ​​thức cơ bản, hãy cùng xây dựng một ứng dụng!




Mô tả dịch vụ

Dịch vụ được tạo cung cấp một ứng dụng blog rất cơ bản. Các tuyến đường sau được xây dựng:

  • GET / :Trả lại blog (sử dụng mẫu để hiển thị).
  • GET /json :Trả lại nội dung blog ở định dạng JSON.
  • POST /new :Thêm một bài đăng mới (tiêu đề, tóm tắt, nội dung) vào blog.

Giao diện bên ngoài của dịch vụ blog hoàn toàn giống nhau đối với mỗi ngôn ngữ. Để đơn giản, MongoDB sẽ được sử dụng làm nơi lưu trữ dữ liệu cho ví dụ này vì nó là nơi đơn giản nhất để thiết lập và chúng tôi không cần phải lo lắng về các lược đồ. Trong một ứng dụng “giống như blog” thông thường, một cơ sở dữ liệu quan hệ có thể sẽ cần thiết.


Thêm bài đăng

POST /new

$ curl --form title='Test Post 1' \
     --form summary='The First Test Post' \
     --form content='Lorem ipsum dolor sit amet, consectetur ...' \
     http://[IP]:[PORT]/new


Xem HTML

GET /



Xem JSON

GET /json

[
   {
      content:"Lorem ipsum dolor sit amet, consectetur ...",
      title:"Test Post 1",
      _id:{
         $oid:"558329927315660001550970"
      },
      summary:"The First Test Post"
   }
]



Cấu trúc ứng dụng

Mỗi ứng dụng có thể được chia thành các thành phần sau:


Thiết lập ứng dụng

  • Khởi tạo ứng dụng
  • Chạy ứng dụng


Yêu cầu

  • Xác định các tuyến đường mà người dùng có thể yêu cầu dữ liệu (GET)
  • Xác định các tuyến đường mà người dùng có thể gửi dữ liệu (POST)


Phản hồi

  • Kết xuất JSON (GET /json )
  • Hiển thị một mẫu (GET / )


Cơ sở dữ liệu

  • Khởi tạo kết nối
  • Chèn dữ liệu
  • Truy xuất dữ liệu


Triển khai ứng dụng

  • Docker!

Phần còn lại của bài viết này sẽ so sánh từng thành phần này cho từng thư viện. Mục đích không phải để gợi ý rằng một trong những thư viện này tốt hơn thư viện kia - mà là để cung cấp một so sánh cụ thể giữa ba công cụ:

  • Bình (Python)
  • Sinatra (Ruby)
  • Martini (Golang)



Thiết lập dự án

Tất cả các dự án đều được khởi động bằng docker và docker-comp. Trước khi tìm hiểu cách khởi động của từng ứng dụng, chúng ta có thể chỉ cần sử dụng docker để khởi động và chạy từng ứng dụng theo cùng một cách - docker-compose up

Nghiêm túc đấy! Bây giờ cho mỗi ứng dụng có một Dockerfile và một docker-compose.yml tệp chỉ định điều gì sẽ xảy ra khi bạn chạy lệnh trên.

Python (bình) - Dockerfile

FROM python:3.4

ADD . /app
WORKDIR /app

RUN pip install -r requirements.txt

Dockerfile này nói rằng chúng tôi đang bắt đầu từ một hình ảnh cơ sở có cài đặt Python 3.4, thêm ứng dụng của chúng tôi vào /app thư mục và sử dụng pip để cài đặt các yêu cầu ứng dụng của chúng tôi được chỉ định trong requirements.txt .

Ruby (sinatra)

FROM ruby:2.2

ADD . /app
WORKDIR /app

RUN bundle install

Dockerfile này nói rằng chúng tôi đang bắt đầu từ một hình ảnh cơ sở có cài đặt Ruby 2.2, thêm ứng dụng của chúng tôi vào /app thư mục và sử dụng gói để cài đặt các yêu cầu ứng dụng của chúng tôi được chỉ định trong Gemfile .

Golang (martini)

FROM golang:1.3

ADD . /go/src/github.com/kpurdon/go-blog
WORKDIR /go/src/github.com/kpurdon/go-blog

RUN go get github.com/go-martini/martini && \
    go get github.com/martini-contrib/render && \
    go get gopkg.in/mgo.v2 && \
    go get github.com/martini-contrib/binding

Dockerfile này nói rằng chúng tôi đang bắt đầu từ một hình ảnh cơ sở có cài đặt Golang 1.3, thêm ứng dụng của chúng tôi vào /go/src/github.com/kpurdon/go-blog thư mục và nhận tất cả các phụ thuộc cần thiết của chúng tôi bằng cách sử dụng go get lệnh.



Khởi tạo / Chạy một ứng dụng

Python (Flask) - app.py

# initialize application
from flask import Flask
app = Flask(__name__)

# run application
if __name__ == '__main__':
    app.run(host='0.0.0.0')
$ python app.py

Ruby (Sinatra) - app.rb

# initialize application
require 'sinatra'
$ ruby app.rb

Golang (Martini) - app.go

// initialize application
package main
import "github.com/go-martini/martini"
import "github.com/martini-contrib/render"

func main() {
    app := martini.Classic()
    app.Use(render.Renderer())

    // run application
    app.Run()
}
$ go run app.go


Xác định lộ trình (GET / POST)

Python (Bình)

# get
@app.route('/')  # the default is GET only
def blog():
    # ...

#post
@app.route('/new', methods=['POST'])
def new():
    # ...

Ruby (Sinatra)

# get
get '/' do
  # ...
end

# post
post '/new' do
  # ...
end

Golang (Martini)

// define data struct
type Post struct {
  Title   string `form:"title" json:"title"`
  Summary string `form:"summary" json:"summary"`
  Content string `form:"content" json:"content"`
}

// get
app.Get("/", func(r render.Render) {
  // ...
}

// post
import "github.com/martini-contrib/binding"
app.Post("/new", binding.Bind(Post{}), func(r render.Render, post Post) {
  // ...
}


Hiển thị phản hồi JSON

Python (Bình)

Flask cung cấp phương thức jsonify () nhưng vì dịch vụ đang sử dụng MongoDB nên tiện ích mongodb bson được sử dụng.

from bson.json_util import dumps
return dumps(posts) # posts is a list of dicts [{}, {}]

Ruby (Sinatra)

require 'json'
content_type :json
posts.to_json # posts is an array (from mongodb)

Golang (Martini)

r.JSON(200, posts) // posts is an array of Post{} structs


Hiển thị phản hồi HTML (Tạo mẫu)

Python (Bình)

return render_template('blog.html', posts=posts)
<!doctype HTML>
<html>
  <head>
    <title>Python Flask Example</title>
  </head>
  <body>
    {% for post in posts %}
      <h1> {{ post.title }} </h1>
      <h3> {{ post.summary }} </h3>
      <p> {{ post.content }} </p>
      <hr>
    {% endfor %}
  </body>
</html>

Ruby (Sinatra)

erb :blog
<!doctype HTML>
<html>
  <head>
    <title>Ruby Sinatra Example</title>
  </head>
  <body>
    <% @posts.each do |post| %>
      <h1><%= post['title'] %></h1>
      <h3><%= post['summary'] %></h3>
      <p><%= post['content'] %></p>
      <hr>
    <% end %>
  </body>
</html>

Golang (Martini)

r.HTML(200, "blog", posts)
<!doctype HTML>
<html>
  <head>
    <title>Golang Martini Example</title>
  </head>
  <body>
    {{range . }}
      <h1>{{.Title}}</h1>
      <h3>{{.Summary}}</h3>
      <p>{{.Content}}</p>
      <hr>
    {{ end }}
  </body>
</html>


Kết nối cơ sở dữ liệu

Tất cả các ứng dụng đang sử dụng trình điều khiển mongodb cụ thể cho ngôn ngữ. Biến môi trường DB_PORT_27017_TCP_ADDR là IP của một vùng chứa docker được liên kết (ip cơ sở dữ liệu).

Python (Bình)

from pymongo import MongoClient
client = MongoClient(os.environ['DB_PORT_27017_TCP_ADDR'], 27017)
db = client.blog

Ruby (Sinatra)

require 'mongo'
db_ip = [ENV['DB_PORT_27017_TCP_ADDR']]
client = Mongo::Client.new(db_ip, database: 'blog')

Golang (Martini)

import "gopkg.in/mgo.v2"
session, _ := mgo.Dial(os.Getenv("DB_PORT_27017_TCP_ADDR"))
db := session.DB("blog")
defer session.Close()


Chèn dữ liệu từ BÀI ĐĂNG

Python (Bình)

from flask import request
post = {
    'title': request.form['title'],
    'summary': request.form['summary'],
    'content': request.form['content']
}
db.blog.insert_one(post)

Ruby (Sinatra)

client[:posts].insert_one(params) # params is a hash generated by sinatra

Golang (Martini)

db.C("posts").Insert(post) // post is an instance of the Post{} struct


Truy xuất dữ liệu

Python (Bình)

posts = db.blog.find()

Ruby (Sinatra)

@posts = client[:posts].find.to_a

Golang (Martini)

var posts []Post
db.C("posts").Find(nil).All(&posts)


Triển khai ứng dụng (Docker!)

Một giải pháp tuyệt vời để triển khai tất cả các ứng dụng này là sử dụng docker và docker -omp.

Python (Bình)

Dockerfile

FROM python:3.4

ADD . /app
WORKDIR /app

RUN pip install -r requirements.txt

docker -omp.yml

web:
  build: .
  command: python -u app.py
  ports:
    - "5000:5000"
  volumes:
    - .:/app
  links:
    - db
db:
  image: mongo:3.0.4
  command: mongod --quiet --logpath=/dev/null

Ruby (Sinatra)

Dockerfile

FROM ruby:2.2

ADD . /app
WORKDIR /app

RUN bundle install

docker -omp.yml

web:
  build: .
  command: bundle exec ruby app.rb
  ports:
    - "4567:4567"
  volumes:
    - .:/app
  links:
    - db
db:
  image: mongo:3.0.4
  command: mongod --quiet --logpath=/dev/null

Golang (Martini)

Dockerfile

FROM golang:1.3

ADD . /go/src/github.com/kpurdon/go-todo
WORKDIR /go/src/github.com/kpurdon/go-todo

RUN go get github.com/go-martini/martini && go get github.com/martini-contrib/render && go get gopkg.in/mgo.v2 && go get github.com/martini-contrib/binding

docker -omp.yml

web:
  build: .
  command: go run app.go
  ports:
    - "3000:3000"
  volumes: # look into volumes v. "ADD"
    - .:/go/src/github.com/kpurdon/go-todo
  links:
    - db
db:
  image: mongo:3.0.4
  command: mongod --quiet --logpath=/dev/null


Kết luận

Để kết thúc, chúng ta hãy xem xét những gì tôi tin là một vài danh mục trong đó các thư viện được trình bày tách biệt với nhau.


Tính đơn giản

Mặc dù Flask rất nhẹ và đọc rõ ràng, ứng dụng Sinatra là ứng dụng đơn giản nhất trong số ba ứng dụng ở mức 23 LOC (so với 46 của Flask và 42 của Martini). Vì những lý do này, Sinatra là người chiến thắng trong hạng mục này. Tuy nhiên, cần lưu ý rằng sự đơn giản của Sinatra là do "ma thuật" mặc định nhiều hơn - ví dụ:công việc ngầm xảy ra ở hậu trường. Đối với người dùng mới, điều này thường có thể dẫn đến nhầm lẫn.

Đây là một ví dụ cụ thể về "ma thuật" trong Sinatra:

params # the "request.form" logic in python is done "magically" behind the scenes in Sinatra.

Và mã bình tương đương:

from flask import request
params = {
    'title': request.form['title'],
    'summary': request.form['summary'],
    'content': request.form['content']
}

Đối với người mới bắt đầu lập trình Flask và Sinatra chắc chắn đơn giản hơn, nhưng đối với một lập trình viên có kinh nghiệm với thời gian sử dụng các ngôn ngữ nhập tĩnh khác, Martini cung cấp một giao diện khá đơn giản.



Tài liệu

Tài liệu về Flask là tài liệu đơn giản nhất để tìm kiếm và dễ tiếp cận nhất. Mặc dù Sinatra và Martini đều được ghi chép đầy đủ, nhưng bản thân tài liệu lại không dễ tiếp cận. Vì lý do này, Flask là người chiến thắng trong hạng mục này.



Cộng đồng

Flask là người chiến thắng trong hạng mục này. Cộng đồng Ruby thường không quá giáo điều về việc Rails là lựa chọn tốt duy nhất nếu bạn cần bất cứ thứ gì ngoài một dịch vụ cơ bản (mặc dù Padrino cung cấp dịch vụ này trên Sinatra). Cộng đồng Golang vẫn chưa có sự đồng thuận về một (hoặc thậm chí một vài) khung web, điều này được mong đợi vì bản thân ngôn ngữ này còn quá non trẻ. Tuy nhiên, Python đã chấp nhận một số phương pháp tiếp cận để phát triển web bao gồm Django cho các ứng dụng web đầy đủ tính năng mới ra mắt và Flask, Bottle, CheryPy và Tornado cho phương pháp tiếp cận vi khuôn khổ.




Xác định cuối cùng

Lưu ý rằng mục đích của bài viết này không phải để quảng bá một công cụ duy nhất, mà là cung cấp sự so sánh không thiên vị về Flask, Sinatra và Martini. Với điều đó đã nói, tôi sẽ chọn Flask (Python) hoặc Sinatra (Ruby). Nếu bạn đến từ một ngôn ngữ như C hoặc Java, có lẽ bản chất kiểu tĩnh của Golang có thể hấp dẫn bạn. Nếu bạn là người mới bắt đầu, Flask có thể là lựa chọn tốt nhất vì nó rất dễ bắt đầu và vận hành và có rất ít “phép thuật” mặc định. Khuyến nghị của tôi là bạn nên linh hoạt trong các quyết định của mình khi chọn thư viện cho dự án của mình.

Câu hỏi? Phản hồi? Hãy bình luận bên dưới. Xin cảm ơn!

Ngoài ra, hãy cho chúng tôi biết nếu bạn muốn xem một số điểm chuẩn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ReadyCloud ReadyShipper X

  2. Đặc quyền của người dùng cơ sở dữ liệu là gì?

  3. Tách chuỗi:Giờ đây với ít T-SQL hơn

  4. Bất ngờ về hiệu suất và giả định:BẬT SỐ KHOẢN

  5. Thử thách đang diễn ra! Kêu gọi cộng đồng tạo trình tạo chuỗi số nhanh nhất