2015/06/18


Matz も驚く Crystal


Crystal

Language Goals Ruby-inspired syntax. Statically type-checked but without having to specify the type ...

http://crystal-lang.org/

ruby と殆ど同じシンタックスが通る様です。

# A very basic HTTP server
require "http/server"

server = HTTP::Server.new(8080do |request|
  HTTP::Response.ok "text/plain""Hello world!"
end

puts "Listening on http://0.0.0.0:8080"
server.listen

しかも native code が吐けるらしい。ならばとベンチマークを取ってみた。CRuby 側は以下の sinatra。CRuby は 2.2.0p0 を使用。

require "sinatra"

set :environment:production

get "/" do
  content_type 'text/plain'
  "Hello world!"
end
$ ab -k -c 10 -n 10000 http://localhost:8000

まずは sinatra

Server Hostname:        localhost
Server Port:            4567

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      10
Time taken for tests:   8.502 seconds
Complete requests:      10000
Failed requests:        0
Keep-Alive requests:    10000
Total transferred:      1620000 bytes
HTML transferred:       120000 bytes
Requests per second:    1176.24 [#/sec] (mean)
Time per request:       8.502 [ms] (mean)
Time per request:       0.850 [ms] (mean, across all concurrent requests)
Transfer rate:          186.08 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     1    8   2.6      8      66
Waiting:        1    8   2.6      8      66
Total:          1    8   2.6      8      67

Percentage of the requests served within a certain time (ms)
  50%      8
  66%      9
  75%      9
  80%     10
  90%     11
  95%     13
  98%     14
  99%     16
 100%     67 (longest request)

そして Crystal

追記: 以下はデバッグビルドの結果でした。その下に続けてリリースビルド時の結果を追記しています。

デバッグビルド

Server Hostname:        localhost
Server Port:            8080

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      10
Time taken for tests:   0.633 seconds
Complete requests:      10000
Failed requests:        0
Keep-Alive requests:    10000
Total transferred:      1010000 bytes
HTML transferred:       120000 bytes
Requests per second:    15802.98 [#/sec] (mean)
Time per request:       0.633 [ms] (mean)
Time per request:       0.063 [ms] (mean, across all concurrent requests)
Transfer rate:          1558.69 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    1   0.2      1       3
Waiting:        0    1   0.2      1       3
Total:          0    1   0.2      1       3

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      1
  98%      1
  99%      1
 100%      3 (longest request)

リリースビルド

Server Software:        
Server Hostname:        localhost
Server Port:            8080

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      10
Time taken for tests:   0.295 seconds
Complete requests:      10000
Failed requests:        0
Keep-Alive requests:    10000
Total transferred:      1010000 bytes
HTML transferred:       120000 bytes
Requests per second:    33888.54 [#/sec] (mean)
Time per request:       0.295 [ms] (mean)
Time per request:       0.030 [ms] (mean, across all concurrent requests)
Transfer rate:          3342.52 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:     0    0   0.1      0       1
Waiting:        0    0   0.1      0       1
Total:          0    0   0.1      0       1

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%      0
  80%      0
  90%      1
  95%      1
  98%      1
  99%      1
 100%      1 (longest request)

比べ物にならなかった。ただ、h2ohttp-server だとファイルをサーブしたとしても 28000req/sec から 30000req/sec は出る環境なので、Crystal のネイティブコードがめちゃくちゃ速いという訳ではない。

Posted at by



2014/03/24


良く分からないけどニーズがある様なので書いた。
1~2時間程度で書けると思ったのに予想以上に ruby 戦闘能力が無くて泣いた。
mattn/mruby-pjson - GitHub
https://github.com/mattn/mruby-pjson
今の所 parse しかないので dump も付けたい。
あとまだまだ色んな所で甘いので直さないといけない。
Posted at by



2014/03/14


ruby のアプリを動かす時にいちいち bundle exec って書くのがダルい。書きたくない。でもシステムに入ってたり違うバージョンの物が動いて変な動作をされても困る。
どうにかしてこのダルさを解消できないかと考えてみた。

まず rbenv を使ってるなら gem でインストールされるコマンドは必ずシェルのラッパとして生成され、そこから本物が起動する様になっている。例えば rails であれば以下の様なシェルになっている。
#!/usr/bin/env bash
set -e
[ -n "$RBENV_DEBUG" ] && set -x

program="${0##*/}"
if [ "$program" = "ruby" ]then
  for arg; do
    case "$arg" in
    -e* | -- ) break ;;
    */* )
      if [ -f "$arg" ]then
        export RBENV_DIR="${arg%/*}"
        break
      fi
      ;;
    esac
  done
fi

export RBENV_ROOT="/home/mattn/.rbenv"
exec "/home/mattn/.rbenv/libexec/rbenv" exec "$program" "$@"
おっと、運良く /usr/bin/env を使ってくれている。つまりはパスを書き換えれば rails とタイプしたコマンドを自前のコマンドに置き換えられるという事だ。
って事で direnv を入れよう。
direnv - unclutter your .profile

Usage Use direnv edit . to open an ".envrc" in your 1EDITOR. This script is going to be executed onc...

http://direnv.net/
$ go get github.com/zimbatm/direnv bash をインタラクティブシェルに使っているなら以下を .bashrc に追加する。
eval "$(direnv hook bash)"
これでこのディレクトリ特有のフックが実行出来る。次に rails や middleman 等を起動しているディレクトリに .envrc というファイルを作ろう。
中身はパスを書き換えるだけ。
export PATH=$PWD/.bin:$PATH
シェルを起動し直すか source ~/.bashrc した後でこのディレクトリに移動すると direnv: error .envrc is blocked. Run `direnv allow` to approve its content. と怒られる。すかさず $ direnv allow を実行しよう。さて、後は .bin というディレクトリを作り、その中に bash というファイルを作る。勘のいい方であればそろそろ気付いたはず。
#!/bin/bash

PATH=`echo $PATH sed 's/^[^:]*://g'` bundle exec "$@"
追加したパスを元に戻して bundle exec "$@" しています。
これでいちいち bundle exec middleman とかしなくても middleman とするだけで同じコマンドが実行出来る様になります。

さようなら、bundle exec、いい思い出をありがとう。

ちなみに shebang が bash じゃなくて perl な物を起動しようとしているなら同様に .bin/perl を書いてしまえば、carton exec にも対応出来るかもしれませんね。
(だらだら書いてますが bundle install --binstubs してそこにパス通すのでいいです)
Posted at by