fast-woothee-pythonを書いていました

少し前の話ですが、 8月頃にwoothee-goにプルリクを送った 流れから中の人に提案していただいて、 woothee-rust をwootheeファミリに追加していただけました。

fast_woothee

その流れからwootheeまわりを調べていると、 速度を求めてか woothee-rustのRubyバインディングfast_woothee というものがありまして、 ほぉという感じで眺めていました。 少し時が経って、じゃぁ実際どれくらい速いのか確認したくなったので、 確認してみるとRubyネイティブ実装の woothee-ruby より遅かったのです。 どうしたものかと思って、 woothee-rustのdatasetまわりのコードをlazy_staticでラップして高速化 しました。 結果2倍ほど高速になりました

 [before]
 $ ruby bench.rb
                  user     system      total        real
 woothee      2.270000   0.020000   2.290000 (  2.309573)
 fast-woothee  2.710000   0.020000   2.730000 (  2.758268)

 [after]
 $ ruby bench.rb
                  user     system      total        real
 woothee      2.240000   0.020000   2.260000 (  2.261497)
 fast-woothee  1.100000   0.010000   1.110000 (  1.134596)

fast-woothee-python

さてここからが本題なのですが、fast_wootheeの流れを受けて Pythonでも同じようなことをしたくなったのでさっくり実装してみました。

fast-woothee-python

モチベーションとしては、以下のようなものでした。

  • Pythonでも同等の高速化が期待できる
  • 一定API自体は固まっておりほぼ変わらないので、 一度拡張を書いてしまえばwoothee-rustをメンテナンスすることで変更に対応でき、 メンテナンスコストを低減できる。
  • RustなPython拡張の事例作り(今後プロダクションで使っていきたい)

結果はこちらも 約3倍程度の高速化が実現 できました。

 ## benchmarker:         release 4.0.1 (for python)
 ## python version:      2.7.13
 ## python compiler:     GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)
 ## python platform:     Darwin-15.6.0-x86_64-i386-64bit
 ## python executable:   ./.virtualenvs/py2713/bin/python
 ## cpu model:           Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
 ## parameters:          loop=100000, cycle=1, extra=0

 ##                                       real    (total    = user    + sys)
 uap                                    0.0813    0.0800    0.0800    0.0000
 uap(non-cache)                        64.3114   63.5200   63.2800    0.2400
 woothee                                3.2219    3.1200    3.1000    0.0200
 fast-woothee                           1.0989    1.1000    1.0900    0.0100

 ## Ranking                               real
 uap                                    0.0813  (100.0) ********************
 fast-woothee                           1.0989  (  7.4) *
 woothee                                3.2219  (  2.5) *
 uap(non-cache)                        64.3114  (  0.1)

 ## Matrix                                real    [01]    [02]    [03]    [04]
 [01] uap                               0.0813   100.0  1352.1  3964.4 79132.1
 [02] fast-woothee                      1.0989     7.4   100.0   293.2  5852.5
 [03] woothee                           3.2219     2.5    34.1   100.0  1996.1
 [04] uap(non-cache)                   64.3114     0.1     1.7     5.0   100.0

uap-python (uap)はキャッシュを内部で持っていて、 一度パースした結果をすぐに返せるので非常に高速になってます。 キャッシュを使わない場合も参考に載せてます。uap(non-cache)

implementation

fast-woothee-pythonはRustコードを書くことでPython拡張が書ける PyO3/pyo3 を使っています。 同じ用途として dgrunwald/rust-cpython が存在するのですが、 私が試した時はPython2向けのビルドがエラーになってしまったのと、 Python3でベンチマークをとってみてもオーバーヘッドがどちらも同じくらいだったので、 pyo3を使った経緯があります。 pyo3の方が活発に開発が行われていますが、rust-cpythonも開発が止まっているわけではないので、 今は状況が変わっているかもしれません。

parse メソッドと is_crawler メソッドの2つしかなく最小限の構成になっているので、 RustなPython拡張の雛形として参考にしていただければと。

RustでPHPビルトインサーバ用のリバースプロキシを書いてみました

kamasu

名前は kamasu です。 RustをPHPのビルトインサーバの前段にカマして並列に処理したい、という目的で書きました。 HTTPSで接続を受けて、通信することも可能です。

       +--------------------+     +----------------------------------------+
       | kamasu(main proc)  | - - |                                        |-+
       |                    | +-->|           php built-in server          | |-+
 HTTP  |    +--------+ HTTP | |+->| (child proc via std::process::Command) | | |
----------->| thread |--------+|  +----------------------------------------+ | |
       |    | (http) |      |  |    +----------------------------------------+ |
       |    +--------+      |  |      +----------------------------------------+
       |                    |  |                     :
 HTTPS |    +--------+ HTTP |  |                     : N procs
----------->| thread |---------+                     :
       |    | (https)|      |
       |    +--------+      |
       +--------------------+

使い方

 $ cargo install --force --git https://github.com/hhatto/kamasu.git
 $ kamasu -S 127.0.0.1:8080

-S -t -c あたりは php コマンドと同じ引数を指定すれば、バインドアドレス、 ドキュメントルート、php.iniファイル(またはディレクトリ)を指定して起動することができます。

-s オプションにアドレスを渡すことでHTTPSのプロキシとして動作させることができます。

軽くベンチマーク

 $ php -S 127.0.0.1:8000 -t ./docroot
 $ ab -n 1000 -c 10 http://127.0.0.1:8000/
         :
 Concurrency Level:      10
 Time taken for tests:   14.320 seconds
 Complete requests:      1000
 Failed requests:        0
 Total transferred:      229000 bytes
 HTML transferred:       96000 bytes
 Requests per second:    69.83 [#/sec] (mean)
 Time per request:       143.200 [ms] (mean)
 Time per request:       14.320 [ms] (mean, across all concurrent requests)
 Transfer rate:          15.62 [Kbytes/sec] received
         :

 $ kamasu -S 127.0.0.1:8000 -t ./docroot
 $ ab -n 1000 -c 10 http://127.0.0.1:8000/
         :
 Concurrency Level:      10
 Time taken for tests:   7.825 seconds
 Complete requests:      1000
 Failed requests:        0
 Total transferred:      305000 bytes
 HTML transferred:       107000 bytes
 Requests per second:    127.79 [#/sec] (mean)
 Time per request:       78.255 [ms] (mean)
 Time per request:       7.825 [ms] (mean, across all concurrent requests)
 Transfer rate:          38.06 [Kbytes/sec] received
         :
 $

モチベーション

手元の開発環境だとPHPのビルトインサーバを使っていて、 ちょっと並列で動かしたいなという場面がでてきたので、 Tokio のサンプルにちょうどいいと思い実装してみました。

アイディア自体は以下のQiita記事を読んで、思い立った次第です。ありがたい。

その他

バイナリのリリースについては、以下を参考にさせていただきました。ありがたい。

GitHubのreleasesページ からバージョンごとのバイナリをダウンロードして使い始めることができます。 今の所x86_64なLinux/macOS環境向けのみ提供しています。

よければ使ってみてください。ではまた

peg-rstを書きました

公開してから日が空いてしまったのですが、 少し前にCのreStructuredTextパーサであるところの peg-rst をリリースしました。

「今までなかった情報は英語で記事を書く」みたいなことを言っておきながら、 英語書くの億劫だしなぁとか思ってたら日が経ってしまいました。 書かないぐらいならせめて日本語で書こうってことで、今キーボードを叩いてます。

以前、GoのreStructuredTextパーサ gorst を書いて、今もメンテナンスしていますが、 もともとCのMarkdownパーサからGoのMarkdownパーサに移植したものをベースにつくったので、 reStructuredTextでGoからCにまた移植できるかなぁと妄想しつつやっと手をつけた感じです。

まだまだバグは多いですが、細々とメンテナンスしていきたいなと思います。

バグ報告でもよいので、気軽に使ってフィードバックいただけるとありがたいです。

goremanを拡張してみた

Magick++ (GraphicsMagick) problems when using drawing text with DrawableFont() on macOS

Lifelog 2017.03

Older Blog Posts