2018年11月7日水曜日

python responder & flask / node.js express

はじめに

HTTPサーバーを作るPythonのresponderというパッケージが新しくKenneth Reitzさんによって作られたということをHacker Newsで読んだので、 使ってみようかと思い、ついでに他のサーバーパッケージも 入れたすごく簡単な動作比較をします。
少ないですが、次のフレームワークを比較します。

 

 

環境構築

pythonとnodejsの環境構築です。


python
$ pipenv --python 3.6
$ pipenv install responder flask
TypeError: 'module' object is not callable エラーが出るとき:
Pipenvのバグで、pip18.1を使っているとエラーがでます。(10/17/2018現在) pip18.0にダウングレードすると直ります。
$ pipenv run pip install pip==18.0

  

node.js (v11.0.0)
$ npm init -y
$ npm i -S express

 

 

REST API(Hello World)

localhost:3000/hello へ GET すると Hello World!が返る基本的なREST APIです。



responder

# server_responder.py

import responder

api = responder.API()

@api.route("/hello")
async def hello(req, resp):
    resp.text = "Hello World!"

if __name__ == "__main__":
    api.run(port=3000)


サーバー開始
$ pipenv run python server_responder.py
INFO: Started server process [91078]
INFO: Uvicorn running on http://127.0.0.1:3000 (Press CTRL+C to quit)


curlでチェック
$ curl localhost:3000/hello
Hello World!$


返ってきました。サーバー側のログも出ています。
INFO: ('127.0.0.1', 53672) - "GET /hello HTTP/1.1" 200

 

 

flask

# server_flask.py

from flask import Flask

app = Flask(__name__)

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


サーバー開始
$ FLASK_APP=server_flask.py pipenv run flask run --port 3000
 * Serving Flask app "server_flask.py"
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)


Flaskでは if __name__ == "__main__": ... でもできますが、コマンドで起動することを推奨しています。
ポートもコマンドで指定します。

curlでチェック
$ curl localhost:3000/hello
Hello World!$


サーバーログ
127.0.0.1 - - [07/Nov/2018 22:17:04] "GET /hello HTTP/1.1" 200 -

 

 

express

// server_express.js

const express = require("express");
const app = express();

app.get("/hello", (req, res) => res.send("Hello World!"))

app.listen(3000, () => console.log("server on"))


サーバー開始
$ node server_express.js
server on


Expressはログを自動で返しません。サーバーが起動したことを示すためにコールバック関数でserver onとコンソールに出力しました。

curlでチェック
$ curl localhost:3000/hello
Hello World!$


ログは一切出ません。

ログを出すには、別のモジュールである morgan をインストールして使います。
$ npm i -S morgan
// server_express.js

const express = require("express");
const app = express();

// morganをミドルウェアとして使う
const logger = require("morgan");
app.use(logger("dev"))

app.get("/hello", (req, res) => res.send("Hello World!"))

app.listen(3000, () => console.log("server on"))


起動してから、curlテストした際のログ
GET /hello 200 7.132 ms - 12

 

 

サーバーサイドレンダリングされたHTMLページ

HTMLを返すエンドポイントを作ります。
サーバーサイドでそのままHTMLを書いても使えますが、変数を渡したりするにはテンプレートエンジンというものを使います。
pythonのパッケージのresponderとflaskではデフォルトでjinja2が使われていて、node.jsでは色々選べますがここではexpressで公式に紹介されているpugを使います。
それぞれ、 Hello, {名前}!と名前の部分を変数としたHTMLを作成します。

 

 

responder

実は上でサーバーを起動した際に、自動でstatic/templates/の二つのファイルがルートに作成されています。ここに返すHTMLを作ります。
自動で作られたtemplates/内にpage.htmlを作り、Jinja templateを使ってテンプレーティングします。

<!-- templates/page.html -->

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>html page</title>
    </head>
    <body>
        <h1>Hello, {{ name }}!</h1>
    </body>
</html>


エンドポイント
# server_responder.py

import responder

api = responder.API()

@api.route("/hello/{name}")
async def hello(req, resp, *, name):
    resp.content = api.template("page.html", name=name)

if __name__ == "__main__":
    api.run(port=3000)


ブラウザでlocalhost:3000/hello/kazuyaにアクセスすると、Hello, kazuya!と表示され、タイトルはhtml pageとなっています。

curlでもテスト
$ curl localhost:3000/hello/kazuya
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>html page</title>
    </head>
    <body>
        <h1>Hello, kazuya!</h1>
    </body>
</html>
このコードを実行した時、エラーが出て、イシューをあげたら直してもらえました。 https://github.com/kennethreitz/responder/issues/76

 



flask

同じJinja2を使ってレンダリングしているので、HTMLは同じで大丈夫です。
気をつけるのは、ここではresponderが自動でtemplatesフォルダを作ってるのでそれを使いますが、flaskだけでやる場合は自分でフォルダを作らないといけないことです。

# server_flask.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/hello/<name>")
def hello(name=None):
    return render_template("page.html", name=name)


結果はresponderと一緒です。

 



express

pugをインストールします。
npm i -S pug


pug は書き方が独特で、yamlみたいな書き方をします。

html
    body
        h1 Hello, #{ name }!


expressにテンプレートエンジンと、HTMLファイルのある場所の設定をします。

const express = require("express");
const path = require("path");

const app = express();

// viewsフォルダを見るように設定
app.set("views", path.join(__dirname, "views"));
// テンプレートエンジンをpugに設定
app.set("view engine", "pug")

app.get("/hello/:name", (req, res) => {
  res.render("page", { name: req.params.name })
})

app.listen(3000, () => console.log("server on"))



結果はpythonのパッケージと同じになります。

 

 

考察

pythonはデコレータを使って、node.jsはコールバック関数を使ってHTTPリクエストに対する挙動をプログラムしています。
responderとexpressは両方エンドポイントで用いる関数にrequest, response的なオブジェクトが渡されることになっていたり、そのうちresponse側のオブジェクトで返答を定義するところが似ています。flaskはそういうのが無いですね。
あとrequestsとexpressではasync/awaitがサポートされているけど、flaskには無い。でもサーバー側で非同期処理ってどのくらいメリットがあるのか自分は知らないです。
pythonのパッケージはログとかテンプレートエンジンとか諸々最初からサポートされているけど、expressは全部自分で入れていかないといけない。Unix的にはexpressの方が良いパッケージなんだろうが、ちょっとめんどくさい。今回までのセットアップでも若干pythonパッケージの方が便利でした。
その代わりパフォーマンスは、間違いなくexpressの方が良いはずです。

2018年10月12日金曜日

久しぶりの投稿(一年の振り返りと今後)

はじめに


ブログをまたやろうと思います。
理由は、転職から1年経ち、自分のキャリアのこととか人生のことなどを振り返って、今後に向けて考えをまとめたくなったからです。
考えをまとめるときは経験上、文章化するのが良いとわかってます。
ただ、幾度とブログやSNS上の個人発信はした期間があったものの、個人的にあまりいい思い出になっていなくて、意図せず人を傷つけるような書き方をしたり、後から見返して穴に入りたくなるようなことを書いたり、そういうことがあってしばらく離れていました。
今回のブログの目的は、自分の考えをまとめることなので、その目的から逸した事とかを勢いで書いたり、思いつくままにつらつらと書き連ねて出版するとかして後から後悔しないように、気をつけようと思います。
今回は、この一年の振り返りをこのタイミングでします。


2018年3月11日日曜日

頭をひねって考え出したDefault Boxesの実装がChainerの実装と構造が一緒で嬉しい

screenを使ってjupyter notebookとか使ってると

セッションが切れても裏で動き続けているという裏技

2018年3月2日金曜日

pytorchでcudaのavailabilityを確かめる

TensorFlowがimportできなくなった。
全然DeepLearningが捗らないのでPyTorchを入れて動かしたらすっごくわかりやすかったから
今後PyTorchやろうかな。



>>> torch.cuda.is_available()
True


nvidia driver と CUDA と cudnn のインストールはここがわかりやすかったしPyTorchでちゃんと動くのでよかった
http://www.python36.com/install-tensorflow-using-official-pip-pacakage/
そもそものTensorFlowは動かないけど





>>> import tensorflow as tf
Illegal instruction (core dumped)
(dl) khatta@ubuntu:~$


同じ事象がCPUサーバーでも起きてたから、何かインストールするときに間違ってるんだと思う
どうしよう。。


PyTorchでDeepLearningできるからいいかな。。