akka.io.Tcpのアクター構成について
こちらからの便乗日記です。
日本一わかりやすいというほどでもない Akka2.2 の IO まわりと Pipeline まわり
http://nekogata.hatenablog.com/entry/2013/06/05/222540
akka-actor 2.2からは(元々実験的(experimental)だった) akka.actor.IO が非推奨になったと聞いて、
新生akka.ioの方を調べています。(こちらも現時点ではexperimental)
akka.actor.IOManagerでエコーサーバ
akka-actorのライブラリにはIOManagerというクラスがあり、こちらを用いることでActorSystemの裏側でネットワークI/Oを管理してくれます。
通常ネットワークI/Oを利用する場合、C言語ならread()やwrite()などの関数を使い、JavaならSocketからInputStream, OutputStreamを取り出して、プログラム上の読み書きするタイミングを明示的にpull型の操作で指定することになります。select, poll, epollなどでI/O多重化させる場合も基本的には同様です。
IOManagerの場合は、裏のActorが非同期にI/Oを管理してイベントがある度に表のActorに通知(IOMessage)を飛ばしてきます。表のActorはこれらに応答することで、push型の処理を実行することができます。
参考:http://doc.akka.io/docs/akka/2.0.4/scala/io.html
以下で想定しているバージョンは Scala 2.9.2 と Akka-Actor 2.0.4 です。
Echoサーバ
単純なEchoサーバを作ってみます。
homebrewでemacsをインストール
homebrew( http://mxcl.github.com/homebrew/ )でemacs23.4をインストールして環境構築中です。
あれこれいじってたら以下の表示が出てなんかおかしなことに。
Warning: arch-dependent data dir (/private/tmp/homebrew-emacs-23.4-P2zw/emacs-23.4/nextstep/Emacs.app/Contents/MacOS/libexec/emacs/23.4/x86_64-apple-darwin10.8.0/) does not exist.
調べてみると、起動時にフルパス指定したほうがいいらしい。
(ref: https://github.com/mxcl/homebrew/issues/6661)
しかし、この「フルパス」が曲者。
こうやってインストールした場合、
brew install emacs --cocoa
emacsコマンドは以下の場所にセットされる。
lrwxr-xr-x 1 User Group 30 3 10 19:35 /usr/local/bin/emacs -> ../Cellar/emacs/23.4/bin/emacs
しかし、ここではなく実際には以下のパスが正しい。
/usr/local/Cellar/emacs/23.4/Emacs.app/Contents/MacOS/Emacs
そこで、homebrewでインストールした場合に常に使えるパス指定として、こんなエイリアスを.zshrcに記述。
alias emacs="$(brew --prefix emacs)/Emacs.app/Contents/MacOS/Emacs"
brewのインストールディレクトリは /usr/local/Cellar/emacs/{version}ってバージョン付きになってしまうので、brew --prefixなどのコマンドで差分を吸収できます。
PostgreSQLのコネクションをいっぱいにして保持するツール
需要あんのかな?
#!/usr/bin/env ruby require 'rubygems' require 'pg' # postgres ## Setting ## ConnectionInfo = { :host => "localhost", :port => 5432, :dbname => "postgres", :user => "postgres", } # get wait_time from ARGV[0] if ARGV.size < 1 puts <<EOS Usage: ruby #{__FILE__} <wait_time> wait_time: Wait <wait_time> seconds with maximum pg connection. ( set <= 0 to infinite, ^C to exit ) EOS exit else wait_time = ARGV[0].to_i end # Create Connections connection_array = Array.new while(connection_array.empty? or connection_array.last.status == PGconn::CONNECTION_OK) begin connection_array << PGconn.new(ConnectionInfo) rescue PGError break rescue Interrupt # with Interrupt connection_array.each { |conn| conn.close } puts "All connection cleared." exit end # p connection_array.size end # Print number of connections. puts "Maximum: #{connection_array.size} connections." # Wait loop. begin if wait_time > 0 wait_time.downto(1) do |i| puts "Remain #{i} second(s)." if i % 10**((Math::log10(wait_time)-0.5).floor) == 0 sleep 1 end else i=1 loop do sleep 1 puts "After #{i} second(s)." if i % 10**((Math::log10(i)).floor) == 0 i += 1 end end rescue Interrupt # if ^C sent, exit with no error. ensure connection_array.each { |conn| conn.close } puts "All connection cleared." end
C言語ことはじめ
改めまして、お仕事でC言語を取り扱うことになって1ヶ月ほど経ちました。
これまでシェル(bash)とかRuby on Railsとかスクリプト系が多くてすっかり忘れている感がありました。
というか、実際のところ大学の実習程度にしかやっておりません。
そんな僕に何が出来るのか。とかくぶち当たって考えていこうと思っている次第です。
さて、C言語では何が必要となるか。思いつくままに列挙してみましょう。
- ポインタの扱い
- バイト単位、ビット単位での対応
- 型の明示的な処理
- 構造体の利用と整理
- 関数の分割方法の整理
適当ですが少しだけ所感を。
- ポインタの扱い
Cをやるとポインタが難しいとか昔は言われてましたが、いざやってみるとそんなに難しい物じゃないです。
どう考えるかというと、単純に変数の格納先の先頭フラグをイメージするだけです。
配列は同じ大きさのメモリ割り当てが連続しているイメージで、インクリメント(+1)で一つ分ずつずらす感じ。
- バイト単位、ビット単位での対応
たとえば int は4バイト、char は1バイトといった単位でメモリを使います。
当然 NxN 行列とかつくると大量に消費しますし、数式の計算ロジックなどではビット単位での演算(AND, OR, ビットシフト, etc)を使うことも考えられます。
関数単位での利用メモリ空間をある程度イメージして、無駄がないか、はみ出す可能性のあるロジックはないか、扱うはずのないデータに干渉していないかなど、十分なマッピングを心がけたほうが良いと思います。
- 型の明示的な処理
Ruby などをやっていると時々忘れるのが型の処理。
例えばintにコマンドライン引数を入れようとしてlongが入ってしまい、値が変わってしまうなどはよくあることで、明示的なキャストや、扱う型が十分見合っているか、事前に型に収まるよう入力チェックが済んでいるか、などをチェックすべきでしょう。
また、最初は型を明示しない内部コード(マクロ定数など)は作成した当人は固定の型に入ると分かっていても、複数人で管理する場合は人為的なミスや仕様変更などが起こり得ることも想定しておき、型チェックを忘れないようにしましょう。
- 構造体の利用と整理
構造体は意味のあるデータのまとまりをメモリ配置(メンバ変数の集まり)で表すものです。先に述べたポインタのインクリメントなどでは、構造体の配列の場合も有効です。
意外と構造体は使われる局面が少ない気もしていますが、ある単位でひとまとまりになっているべきデータは構造体にして整理すべきでしょう。
理由は例えば関数の入出力にchar*やintなどで引数の多い構成になっていた場合、つぎに変数が増えた途端に改修箇所が増え、改修漏れの原因につながります。
構造体の持つ意味をきちんと定めて、そのデータ単位を扱う関数であると明示すべきでしょう。
ただし、むやみに構造体宣言をすると何をする単位かわからなくなるため、DBのモデル定義のような観点は必要でしょう。
- 関数の分割方法と利用
関数の中身はできるだけすっきりとすべきです。
どういう意味ですっきりかというと、「この関数は何をするための関数で、それを分割するといくつかのプロセスからなる」事を明示でき、「いくつかのプロセス」が他の人にも分かりやすいことが大切だと思っています。
例えばイベントループを持つようなプログラムであれば
- main
- コマンドライン引数処理
- 入力値チェック
- 型変換
- メインループに引き渡す前処理
- 変数一覧の確認(抜け漏れの無いよう一覧化や構造体化)
- 引き渡す変数の初期化処理
- メインループで行われるべきルーチン
- イベントコールバックの登録
- メインループ終了後の処理
- free()などのメモリ管理
- 適切な値で終了コードが返ってきたかチェック
- コマンドライン引数処理
などなど、まずは大雑把な流れがあり、そこから細かい処理に派生していきます。
この流れをささっとつかめることを大切に、一つ一つの関数を記述出来れば良いと思います。
また、部分関数化するに当たり以下のことに気をつけておきたいと思っています。
- 部分関数は一度しか使わなくても、細かくても、見通しを悪くする部分があれば処理のカプセル化出来る部分を探して作成すべき。
- 入力されるべきデータや書込み先のポインタを明示する。不必要なものは入れないし、必要であれば必ず明示する。グローバル変数を使わない。
細かいところだと思うのですが、自分のセンスを問うために、よりブラッシュアップして挑みたいと思います。
そんなわけで「初心者がなにかほざいている」程度に思っていただければと思いますが、これからも成長出来ればと思います。