_J Blog

学んだ事のまとめやメモなどが中心です

method_missingの速度計測

遅くなるとは聞いていたが、どんなもんか興味で単純な関数呼び出しでのベンチマークをしてみた。

method_missing と 通常呼び出しの検証結果

user system total real
通常呼び出し 0.000000 0.000000 0.000000 0.000029
method_missing 0.000000 0.000000 0.000000 0.000056

ざっくり見てみたところ
method_missing を利用したときは通常呼び出しの約2倍程度遅い


下記ベンチマークコード(ruby1.9.2-p180)

require 'benchmark'
require 'pp'
class MethodTest
  def method_missing(method_name, *args)
    args
  end
  def test(test)
    return test
  end
end
a = MethodTest.new
puts Benchmark::CAPTION
pp Benchmark.measure {
  10000.times do |i|
    a.test('pool')
  end
}
pp Benchmark.measure {
  10000.times { |i| a.hoge('pool')
  }
}

クラスインスタンス変数とスコープ

気になったので、調べてみた

module Hoge
  module Moge
    class Test
      # クラスインスタンス変数
      @hoge= ->{ p 'called!!'; 'aaaa'}.call
      # 特異メソッド
      def self.get
        p @hoge
      end
      # インスタンスメソッド
      def get
        p @hoge
      end
    end
  end
end

# クラスメソッドはクラスのインスタンス変数を見ることができる。
# 最初に読み込まれたタイミングで初期化がはしる
Hoge::Moge::Test.get
#=> called!!
#=> aaaa

# インスタンスメソッドはクラスインスタンス変数を見ることができない。
Hoge::Moge::Test.new.get
#=> nil

# クラスインスタンス変数の初期化は
# 最初に読み込まれたタイミングの一度のみしか走らないようです。
Hoge::Moge::Test.get
#=> aaaa


下記のようにクラス変数にするとどのメソッドからでも参照できます。

module Hoge
  module Moge
    class Test
      # クラスインスタンス変数
      @@hoge= ->{ p 'called!!'; 'aaaa'}.call
      # 特異メソッド
      def self.get
        p @@hoge
      end
      # インスタンスメソッド
      def get
        p @@hoge
      end
    end
  end
end

# クラスメソッドはクラス変数を見ることができる。
Hoge::Moge::Test.get
#=> called!!
#=> aaaa

# インスタンスメソッドはクラス変数を見ることができる。
Hoge::Moge::Test.new.get
#=> aaaa

SQLite3::ReadOnlyException のエラー

ちょっとサイト作ってるときに、さっきまで普通に動作していたのに、

rake db:migrate:reset

を実行して、ブラウザから確認しようと思ったら、

SQLite3::ReadOnlyException : attempt to write a readonly database

との文字が。

調べてみると、どうやらパーミッションの問題のようです。
SQLite3::ReadOnlyException: attempt to write a readonly database

確認してみると、rootでコマンド実行してたから
sqliteのdbファイルのパーミッションがrootになってました・・・
$ chown user.user dbファイル名
で権限を変更して、もうブラウザで再チャレンジしたらうまくいきました。


おそくなりましたが、あけましておめでとうございます。

特定のインスタンスのみにメソッドを追加する

作成したインスタンスのみメソッド追加するやり方がわからなくて、
試してみたのでメモ

下記ソースコードは Test クラスのインスタンスの a に対して、
特異メソッドを追加してみたサンプルです。

class Test
  def hoge
    p 'pp'
  end
end

a = Test.new
a.hoge
#=> 'pp'

# aの特異クラスに対して特異メソッドを定義する
class << a
  def hoge
    p 'hogehgoe'
  end
end

a.hoge
#=> 'hogehoge'

# 新規クラス作成して確認
b = Test.new

b.hoge
#=> 'pp'
# ほかのインスタンスに影響がない事がわかる

#以下のように書いても同じ
def a.hoge
  p 'hogehogehoge'
end

a.hoge
#=> 'hogehogehoge' 

Yuguiさんのこの記事がとても勉強になりました。
http://yugui.jp/articles/768

継承チェーンなどの、仕組みを分かって行けると楽しいですね。
もっと勉強します・・・

ターミナル上のコマンドで並列処理を行う

パフォーマンスや複数プロセスに関する検証したかった時に知ったのでメモ*1

yes | head -{全部で何度実行するか} | xargs -L {引数の個数(基本1でよいはず)} -P {同時プロセス数} {実行コマンド}

たとえば、test.shを10個のプロセスを立ち上げて
並列に実行したいときは下記のようになる

yes | head -10 | xargs -L 1 -P 10 sh test.sh

*1:yes コマンドも初めて知りました・・・お恥ずかしい

DotCloud で Node.js を 使う

本日は楽天テクノロジーカンファレンスに参加してきました。
いろいろと興味深い話が聞けましたが、それはまた機会があれば。

ホントいまさらって感じですが、DotCloud使ってみようかなと思い立って使ってみました。
最初は、Python が 2.4 の状態だったので dotcloud の cli をインストールするときに

"'str' object has no attribute 'format'"

というエラーが起きてました。
調べてみたところ、これは

format method was introduced in python 3.0 and backported only to 2.6

http://stackoverflow.com/questions/792721/attributeerror-str-object-has-no-attribute-format

との事でしたので、 Python をアップデートするところから書いてみます。

■準備

1.pythonのバージョン確認
$ python 
Python 2.4.3 (#1, Nov 11 2010, 13:30:19) 

と 2.4 系だったので、2.6をyumでインストールします。

まず、epelレポジトリを追加。

$ rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm

これで /etc/yum.repo.d/epel.repo が追加されているので、これを使ってインストールします。

$ yum -y install python26 --enablerepo=epel
2.easy_install のインストール

ソースのダウンロード(python2.6以上を使って行うこと)してインストールします。

$ wget http://peak.telecommunity.com/dist/ez_setup.py
$ sudo /usr/bin/python26 ez_setup.py

確認します。

$ sudo easy_install
error: No urls, filenames, or requirements specified (see --help)
3.dotcloudのcliインストール

下記コマンドでpipも一緒にインストールします。

$ sudo easy_install pip && sudo pip install dotcloud

確認と、APIキー(http://www.dotcloud.com/accounts/settings に書いてあります) を入力します。

$ dotcloud
Warning: /root/.dotcloud/dotcloud.conf does not exist.
Enter your api key (You can find it at http://www.dotcloud.com/accounts/settings): {ここにAPIキーを入力}

■ node.jsのプロジェクトをつくる & DotCloudの設定

"testapp" というアプリケーション名でデプロイしてみます。
今回は node.js でやります。

1.dotcloudに"testapp"というアプリケーション作成
$ dotcloud create testapp
Created application "testapp"
2.Projectディレクトリ & アプリケーションのディレクトリ作成
$ mkdir test-nodejs-dotcloud
$ mkdir test-nodejs-dotcloud/nodetestapp

dotcloudの設定ファイル dotcloud.yml を作成します

$ vim test-nodejs-dotcloud/dotcloud.yml

下記を記述します。

# dotcloud.yml
www: 
  type: nodejs
    approot: nodetestapp

管理ファイル supervisord.conf を作成します。

$ vim test-nodejs-dotcloud/nodetestapp/supervisord.conf

下記を記述します。

# supervisord.conf
[program:node]
command = node server.js
directory = /home/dotcloud/current

node.js の サンプルファイルを作成します

$ vim test-nodejs-dotcloud/nodetestapp/server.js

下記を記述します。

# server.js
var http = require('http');
http.createServer(function (req, res){
      res.writeHead(200, { 'Content-Type': 'text/plain' });
          res.end('Node Test Application!');
}).listen(8080);

■とりあえず、デプロイしてみる

下記コマンドを実行してデプロイします。

$ dotcloud push testapp testapp/

# upload testapp/ ssh://dotcloud@uploader.dotcloud.com:443/testapp# rsync
Pseudo-terminal will not be allocated because stdin is not a terminal.
building file list ... done
./
dotcloud.yml
nodetestapp/
nodetestapp/server.js
nodetestapp/supervisord.conf

sent 574 bytes  received 98 bytes  103.38 bytes/sec
total size is 308  speedup is 0.46
11:25:26 ---> Deploy of "testapp" scheduled for revision rsync-1321701925580 at 2011-11-19 11:25:26
11:25:26 ---> Initializing new services... (This may take a few minutes)
11:25:26 [www.0] Initializing...
11:25:40 [www.0] Service initialized
11:25:40 ---> All services have been initialized. Deploying code...
11:25:40 [www.0] The build started
11:25:41 [www.0] Fetched code revision rsync-1321701925580
11:25:47 [www.0] node: stopped
11:25:48 [www.0] node: started
11:25:48 [www.0] The build finished successfully
11:25:48 ---> Deploy finished

Deployment finished. Your application is available at the following URLs
www: http://testapp-xxxxx.dotcloud.com/

これで、デプロイは完了です。

デプロイ時に表示されたメッセージの最後にあるURL

http://testapp-xxxxxx.dotcloud.com/

にアクセスして、 "Node Test Application!!" と表示されていれば成功です。
噂どうり簡単ですね!

最近、DotCloudから「Now supporting MongoDB Replica Sets」とお知らせが来ていたので、
その辺りも試しつつ、今度は Node.js + MongoDB のアプリケーションをデプロイしてみたいと思います。

ありがとうございました。