メモ: coffeescriptつこうてみた

今作ってるモノで試しにCoffeeScript使ってみたら存外に書きやすく、かつ楽しかったのでメモ。

CoffeeScriptとは

本家
CoffeeScriptRuby,Python,Haskellから影響を受けたプログラミング言語です。
CoffeeScriptの文法にしたがって書いたものをcoffeeコマンドでコンパイルするとJavaScriptになります。

要するに、JavaScriptシンタックスが嫌いとか、JavaScriptゴチャゴチャしがちでなんとかしたいとか、Webブラウザで実行するスクリプトRubyとかPythonとかHaskellとかみたいに書きたいよーとか思ってる人にはおすすめです。

長所と短所

まだ使い始めて1週間くらいなのですが、現時点で感じることは

長所

  • 同じ事をするにもJavaScriptよりコード量が少なくてすむ(Wikipediaによると1/3)
  • 吐き出すのがJavaScriptなので、うまく動かない際にも、何が起こってるのか理解しやすい
  • 書いてて気持ちいい
  • 読みやすい

短所

  • ブラウザのエラー出力は、コンパイル結果のJavaScript上の位置を示すので、そこからCoffeeScript上の間違いを自分で探す必要あり
  • 一部、IenternetExplorer8では実行できないJavaScriptを吐き出す


インストール
インストールにはNode.jsが必要です。Ubuntuなら

$ sudo apt-get install nodejs

です。Macとかでも、多分homebrewとかportsとかにあると思います。たぶん。

Node.jsが入ったら、あとはnpmコマンドでインストールですが、システム全体で共用するなら

$ sudo npm install -g coffee-script

あるいは、なにかしらのプロジェクトを作ってそのプロジェクトディレクトリ内にインストールしたいなら

$ mkdir hoge_project
$ cd hoge_project
$ npm install coffee-script

てやります。

Hello World
とりあえず、最初のCoffeeScriptを作ってみます。
emacsなど好みのエディタで"helloworld.coffee"というファイルを新規作成し、以下のようにかきます。

alert "hello world"

コンパイルしてみます。

$ coffee -c helloworld.coffee

helloworld.jsというファイルができたと思います。中身を見てみます。

// Generated by CoffeeScript 1.4.0
(function() {

  alert("hello world");

}).call(this);

このJavaScriptをブラウザから呼ぶためにHTMLファイルを用意します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>はじめてのCoffeeScript</title>

    <script src="helloworld.js"></script>
	
  </head>
  <body>
  </body>
</html>

Ajaxとかするわけじゃないので、このままHTMLファイルダブルクリックで開けば実行できます。

ある程度大きなプロジェクトではまとまった機能毎にクラスにまとめるとかするといいと思います。

class ClassSample

  # インスタンス変数
  name: null

  # 他の関数の呼び出しは "@間数名()" で
  start_sample: () ->
    @hello()
    @name = "shin"
    @my_name()
    @map_sample()  

  # Rubyみたいに、引数にデフォルト値を指定できます
  # Rubyみたいに、文字列に#{}で値を埋め込めます
  hello: (str = "world")->
    alert "hello #{str}"

  # インスタンス変数の参照は "@変数名" で
  my_name: () -> 
    alert "myname is #{@name}"

  # 配列内の各要素に処理を施した新たな配列をかえします
  # 無名関数は "(引数) -> 処理" です
  map_sample: () ->
    array = [1,2,3,4,5,6]
    new_array = array.map (e) -> e * e
    console.log new_array

Rubyユーザが気をつけるべきことは、CoffeeScriptではブロックの終わりのendがいらないってことです。
この辺はPythonの影響があるらしく、インデントでブロックレベルを表現します。
たとえば条件分岐などは

a = 10

if a > 11
   alert "10より大きい"
else
   alert "10以下"

てな具合です。classや関数、ループなども同様となります。

コンパイルするとこうなります

$ coffee -c class_sample.coffee
// Generated by CoffeeScript 1.4.0
(function() {
  var ClassSample;

  ClassSample = (function() {

    function ClassSample() {}

    ClassSample.prototype.name = null;

    ClassSample.prototype.start_sample = function() {
      this.hello();
      this.name = "shin";
      this.my_name();
      return this.map_sample();
    };

    ClassSample.prototype.hello = function(str) {
      if (str == null) {
        str = "world";
      }
      return alert("hello " + str);
    };

    ClassSample.prototype.my_name = function() {
      return alert("myname is " + this.name);
    };

    ClassSample.prototype.map_sample = function() {
      var array, new_array;
      array = [1, 2, 3, 4, 5, 6];
      new_array = array.map(function(e) {
        return e * e;
      });
      return console.log(new_array);
    };

    return ClassSample;

  })();

}).call(this);

ただ、これだと外部から呼び出せません。
外部から呼び出せるようにするには、コンパイルオプションに-b(--bare)を付加します。

$ coffee -bc class_sample.coffee

できあがったものはこうなります。

// Generated by CoffeeScript 1.4.0
var ClassSample;

ClassSample = (function() {

  function ClassSample() {}

  ClassSample.prototype.name = null;

  ClassSample.prototype.start_sample = function() {
    this.hello();
    this.name = "shin";
    this.my_name();
    return this.map_sample();
  };

  ClassSample.prototype.hello = function(str) {
    if (str == null) {
      str = "world";
    }
    return alert("hello " + str);
  };

  ClassSample.prototype.my_name = function() {
    return alert("myname is " + this.name);
  };

  ClassSample.prototype.map_sample = function() {
    var array, new_array;
    array = [1, 2, 3, 4, 5, 6];
    new_array = array.map(function(e) {
      return e * e;
    });
    return console.log(new_array);
  };

  return ClassSample;

})();

これをよびだすHTMLファイルを用意します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>はじめてのCoffeeScript</title>

    <script src="class_sample.js"></script>
    <script>
      var sample = new ClassSample();
      sample.start_sample();
    </script>

  </head>
  <body>
  </body>
</html>

HTMLダブルクリックで実行できます。

自動コンパイルとか

ここで、ファイルを編集する度にコンパイルするの面倒くさいですよね?
coffeeコマンドにはファイルを監視してて、変更されたらそのファイルを自動的にコンパイルしてくれるオプションがあります。
"-w"をつければ自動コンパイルです。

$ coffee -wc class_sample.coffee

さっきの-bと合わせると

$ coffee -wbc class_sample.coffee

また、ソースファイルの場所とJavaScriptの吐き出し先を指定するとこんな感じです。

$ coffee -wbc -o js/build src/coffee/*.coffee

CoffeeScriptにはcakeというコマンドがあってCakefileを作っておくとタスクが自動化できます。

sys  = require "sys"
fs   = require "fs"
exec = require("child_process").exec
util = require "util"

COFFEE = "coffee"
OPTION = "-cb"
WATCH_OPTION = "-wbc"
SRCDIR = "./"
OUTDIR = "js/build"

#
# @desc 与えられたオプションでコンパイルします
# 
compile = (option) ->
  util.log "compiling coffee..."
  command = "#{COFFEE} #{option} -o #{OUTDIR} #{SRCDIR}/*.coffee"

  exec command, (error, stdout, stderror) ->
    util.log error if error
    util.log stdout if stdout
    util.log stderror if stderror

    if error
      util.log "failure"
    else
      util.log("ok")
  

task "build", "compile coffee to java script", ->
  compile(OPTION)

task "watch", "compile coffee to java script", ->
  compile(WATCH_OPTION)

上記だと、"cake build"とかやるとコンパイルできます。
ただ、これ、コンパイルエラーが出力されないんですよね... たぶん僕が何か間違ってるんでしょうが。。

まあこれくらいの内容なら普通にMakefileでも書けます。

COFFEE=coffee

src_dir=.
out_dir=js/build

all: coffee

coffee:
	@$(COFFEE) -bc  -o ${out_dir} ${src_dir}/*.coffee

coffee-auto:
	@$(COFFEE) -wbc -o ${out_dir} ${src_dir}/*.coffee

clean:
	rm js/build/*.js

ビルドするコマンドが make coffee なんてちょっとオシャレですね(ぉ

今回はここまで。

Ruby + dino で、RubyからArduinoを制御してみた

昨年末にArduino買ってちょくちょく遊んでます。オープンソースの基板で、デジタル入力14点(うち6点は出力として使用可)、アナログ入力6点を持ち、3000円未満と遊ぶにはちょうどいい金額と機能。

ただ、これCによく似たArduino言語でコード書くんですよね。当然、軟弱者の私としましては慣れ親しんだRubyでコードかけないかなって思って調べてみました。

まっさきに調べたのは組み込み向けのRuby、mrubyでいけないかってことでしたが手元にあるArduino Unoではリソース的に厳しそうです(てか実際やってみましたが、リソース以前にコンパイル通らず。

ちなみにUnoよりリソースに余裕のあるArduino DueとChipKit32ではmrubyが動いてるらしく、mrubyのリポジトリにそれ向けのビルドセッティングが入ってたりします。
https://github.com/mruby/mruby/tree/master/examples/targets

で、じゃあArduinoは入出力として使って、BeagleboardとかRaspberryPiとかと組み合わせ使うのはどうなんだろうってまた調べてたらdinoというありがたいgemがありました。

のでそれ使ってみます。

Arduinoの用意

Arduinoの基板はスイッチサイエンスでLEDやジャンパと一緒に4000円ほどで売ってます。
もっとも標準的なUnoでデジタルが14点、アナログが6点あります。

ArduinoIDEがまだ落としてない場合はこれを落としておきます。
Arduino-Software


Arduinoへスケッチをアップロード

dinoのリポジトリにあるdu.inoをダウンロードして、適当なところに保存。Arduino IDEで開きます。
Arduino IDEでdu.inoをコンパイル・基板にアップロードします。

以上でArduino側の用意は終わりです。ここまでやったらArduino IDEは終了してかまいません。

dinoライブラリの準備

dinoはgemにありますので、これをインストールします。

$ sudo gem install dino

Rubyからarduinoを制御してみる

とりあえず、ためしにLEDのチカチカやってみます。
これまた親切丁寧に配線図?があるのでこのとおりにLEDをさします。

試しにirbから制御してみます。

require "dino"
=> true

board = Dino::Board.new(Dino::TxRx.new)
=> #<Dino::Board:0x.....

led = Dino::Components::Led.new(pin: 13, board: board)
=> #<Dino::Components::Led:0x.....

ここまでで13番のデジタル入出力を制御する準備ができました。
では13番にデジタル出力してLEDを光らせてみます。

led.send :on


おお〜(ざわざわ

では消してみます。

led.send :off


消えましたw

とりあえず今回はここまでですが、他にもいろいろとできそうなので、調べてみます。できたらZigBeeと組み合わせてセンサーネットワークとか作ってみたい。

Phabricatorセットアップした時のメモ

継続的に使うかどうかはこれからですが、コードレビューツールのPhabricatorをセットアップしてみました。
なんでもFacebook内部で使われていたものがオープンソースになったものだとか。
もっともPhabricatorはコードレビューだけじゃなくてバグトラックやレポジトリブラウザなど色々多機能なようです。

goo Wikipediaより

Released in early 2011, Phabricator is an open source collection of web applications 
originally developed at Facebook where it is used there by the engineering team. It 
includes applications for common, collaborative software engineering tasks, such as code 
review, repository viewing, bug and issue tracking, a pastebin, and other applications 
geared toward collaboration of software engineers. It is humorously themed, aiming to 
make tasks like code review be more enjoyable.

本家サイトはこちら
http://phabricator.org/

セットアップ

セットアップの仕方はこちらにあります。
Installation Guide

OSはLinux的なOSなら良し、みたいなことが書いてあります。MacOSXもいけるようですね。試してませんが。
私はXen上のDebian GNU/Linux squeeze で行いました。

まずは依存関係から以下が必要。

あとインストール時にgitが必要でした。

Debianなので全てaptで入れました。

$ sudo aptitude install mysql-server mysql-client 
$ sudo aptitude install libapache2-mod-php5 php5-curl php-apc php5-mysql

それと、ユーザ登録したときなどにメールを送信する必要があり、PHPから直接SMTPサーバに
送信する方法と、ローカルのsendmailコマンドを使う方法があるのですが、私は後者を
設定しました。というかPHPから直接送るのはうまくいきませんでした。私がPHPをよく知らないせいだと思いますが。
なのでsendmailコマンドを入れるためにpostfixをインストール

$ sudo aptitude install postfix

MySQLのセットアップ
といってもPhabricator用のユーザを作るだけですが。

$ mysql -uroot -p
Enter password:(パスワード入力)

GRANT ALL PRIVILEGES ON *.* TO phab@localhost IDENTIFIED BY 'pass' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO phab@"%" IDENTIFIED BY 'pass' WITH GRANT OPTION;


Phabricatorのインストール

私は"/usr/local/phabricator"というディレクトリを切ってそこで作業をしました。

$ sudo mkdir /usr/local/phabricator
$ sudo chown myuser:myuser /usr/local/phabricator
$ cd /usr/local/phabricator
$ git clone git://github.com/facebook/libphutil.git
$ git clone git://github.com/facebook/arcanist.git
$ git clone git://github.com/facebook/phabricator.git
$ cd phabricator
$ git submodule update --init

設定
設定関係はConfiguration Guide

設定ファイルを作ります。

$ cd /usr/local/phabricator/phabricator/conf
$ mkdir custom
$ vi custom/myconfig.conf.php

conf/custom/myconfig.conf.php の内容はこんな感じです。

<?php
return array(

  // Important! This will put Phabricator into setup mode to help you
  // configure things.

  'phabricator.setup' => true,

  // This will be the base domain for your install, and must be configured.
  // Use "https://" if you have SSL. See below for some notes.
  'phabricator.base-uri' => 'http://192.168.0.100/',

  // Connection information for MySQL.
  'mysql.host' => 'localhost',
  'mysql.user' => 'phab',
  'mysql.pass' => 'pass',

  // Basic email domain configuration.
  'metamta.default-address' => 'review@mydomain.co.jp',
  'metamta.domain'          => 'mydomain.co.jp',
  'metamta.mail-adapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter'

  // NOTE: Check default.conf.php for detailed explanations of all the
  // configuration options, including these.

) + phabricator_read_config_file('production');
?>

ここでは稼働ホストがローカルネットワークの192.168.0.100と仮定しています。

このファイルを設定ファイルとして読み込むように~/.bashrcに保存しておきます。

$ vi ~/.bashrc

export PHABRICATOR_ENV=custom/myconfig

保存して終了。

そしてデータベースの初期化。

$ cd /usr/local/phabricator/phabricator/
$ ./bin/storage upgrade 

Apacheの設定
このホストでは他に用途もないのでApacheはPhabricator専用にしました。

$ sudo vi /etc/apache2/sites-enabled/000-default

こんなかんじで

<VirtualHost *:80>
        ServerAdmin webmaster@localhost

        DocumentRoot /usr/local/phabricator/phabricator/webroot

        RewriteEngine on
        RewriteRule ^/rsrc/(.*)     -                       [L,QSA]
        RewriteRule ^/favicon.ico   -                       [L,QSA]
        RewriteRule ^(.*)$          /index.php?__path__=$1  [B,L,QSA]

        SetEnv PHABRICATOR_ENV custom/myconfig

        ......

あとはrewriteが使えるようにしておきます。

$ sudo a2enmod rewrite

ここまでやったらApache再起動。

$ sudo /etc/init.d/apache2 restart

で、この場合は http://192.168.0.100 にブラウザでアクセスすると各種設定が実行されるはず。
多分途中でFailureが出ていろいろ言われるのでその都度修正をかけます。

いろいろ修正をかけて、完了のメッセージが出たら先ほどの設定ファイルから"'phabricator.setup' => true"の行をコメントアウトします。
conf/custom/myconfig.conf.php

<?php
return array(

  // Important! This will put Phabricator into setup mode to help you
  // configure things.

  //'phabricator.setup' => true, <=コメントアウト

   ....

それから最初のユーザを作ります。2人目からはWeb画面上で作れます。

$ cd /usr/local/phabricator/phabricator/
$ ./bin/accountadmin


そして再び http://192.168.0.100 にアクセスするとトップ画面が表示されるはず。

Sphinx + blockdiag + seqdiag + nwdiag + actdiag でドキュメント書いて日本語PDFへ出力したメモ

Sphinxのインストール

Macであればhomebrewでインストールできますが、残念ながらそのままではPDF形式で書き出す時に日本語が使えません。既にインストール済みの場合はパッチを当てる事もできますが、ここはパッチ済みのものをインストールします。

なお、ここで使っている"easy_install"コマンドはPythonのパッケージ管理スクリプトです。MacOSXであればはじめからPythonが入っていますので、このコマンドは特に何もしなくても使えるはずです。

   $ easy_install https://bitbucket.org/sphinxjp/website/downloads/Sphinx-1.1.2sphinxjp-latex.tar.gz

Latexのインストール

Ubuntu Linux
aptで入れられます。なんか色々インストールしてようやく日本語PDF出力できるようになりました。
無駄な事もしてるかもしれませんが、とりあえずやったことまるっと書いておきます。

  $ sudo apt-get install texlive texlive-base texlive-latex3 \
                         platex-bin okumura-clsfiles ptex-base \
                         ptex-bin dvipsk-ja xdvik-ja ptex-jisfonts \
                         gs-cjk-resource jmpost dvipdfmx \
                         texlive-math-extra okumura-clsfiles \
                         jbibtex-bin mendexk
  $ sudo apt-get install texlive-latex-extra nkf dvipng
  $ sudo apt-add-repository ppa:texlive-backports/ppa
  $ sudo apt-get update
  $ sudo apt-get install texlive-lang-cjk
  $ sudo apt-get install xdvik-ja
  $ sudo apt-get install texlive-latex-extra
  $ sudo apt-get install texlive-fonts-recommended
  $ sudo apt-get install ttf-sazanami-gothic ttf-sazanami-mincho

MacOSX
Sphinxをインストールすれば、既にHTML等への書き出しはできますが、PDFに書き出すにはLatexが必要です。

MacではTexLive( http://www.tug.org/mactex/2011/ )をインストールすればLatexと各種付属コマンドが使えるようになります。

また、MacでのTexliveのインストール方法や各種設定は
Mac-Tex Wiki 奥村研究所
が詳しいです。


ここではTexLive-2011のトップページから最新のMacTexをダウンロードしてインストールします。

ダウンロードページ http://www.tug.org/mactex/2011/



blockdiagのインストール

blockdiagはブロック図生成ツールでSphinxと連携する事ができます。
blockdiagのインストールはeasy_installから行えます。

   # easy_install blockdiag

更にSphinxのblockdiag拡張をインストールします。

   # easy_install sphinxcontrib-blockdiag

seqdiagのインストール

seqdiagはシーケンス図生成ツールでSphinxと連携する事ができます。
seqdiagのインストールはeasy_installから行えます。

   # easy_install seqdiag

更にSphinxのseqdiag拡張をインストールします。

   # easy_install sphinxcontrib-seqdiag

nwdiagのインストール

nwdiagはネットワーク図生成ツールでSphinxと連携する事ができます。

nwdiagのインストールはeasy_installから行えます。

   # easy_install nwdiag

更にSphinxのnwdiag拡張をインストールします。

   # easy_install sphinxcontrib-nwdiag

また、シスコルータのアイコンを使用する為の拡張をインストールします

   # easy_install blockdiagcontrib-cisco

利用出来るアイコンは `シスコアイコン一覧 を参照してください。

追記

私のMacOSX環境ではシスコルータを使おうとすると"decoder jpeg not available"というエラーがでて使えませんでした。回避するには一旦PILを削除して入れ直します。

   # brew install libjpeg (既に存在するというメッセージが出る事を確認)
   # mv /Library/Python/2.7/site-packages/PIL-1.1.7-py2.7-macosx-10.7-intel.egg /tmp/
   # easy_install pil

actdiagのインストール
nwdiagはネットワーク図生成ツールでSphinxと連携する事ができます。

nwdiagのインストールはeasy_installから行えます。

   # easy_install actdiag

更にSphinxのactdiag拡張をインストールします。

   # easy_install sphinxcontrib-actdiag

以上でセットアップ完了。

sphinx-quickstartによるプロジェクト生成

プロジェクトの生成はコマンドで行います。

   $ sphinx-quickstart

いくつか質問されます。絶対に回答しなければならないのは、次の項目です。後はEnterキーだけで大丈夫です。

  • プロジェクト名
  • バージョン番号
  • 著者の名前

プロジェクトの初期設定

日本語PDFを書き出し、さらにblockdiag等によるダイアグラム拡張を有効にするにはプロジェクト毎に以下の設定を行う必要があります。

プロジェクトディレクトリの直下にあるconf.pyを編集します。

   # 言語の設定(既にあるので変更)
   language = 'ja'
   
   # LaTeX の docclass 設定(新規で追加)
   latex_docclass = {'manual': 'jsbook'}
   
   # Enabled extensions(既にあるのでblockdiag,seqdiag,nwdiag拡張を追加)
   extensions = ['sphinxcontrib.blockdiag', 'sphinxcontrib.seqdiag', 'sphinxcontrib.nwdiag', 'sphinxcontrib.actdiag']

   # Fontpath for blockdiag (truetype font) (新規追加する)

   # Mac OSXでOsakaフォントを使う場合
   blockdiag_fontpath = '/Library/Fonts/Osaka.ttf'

   # Ubuntu Linuxでsazanami-minhchoを使う場合
   blockdiag_fontpath = '/usr/share/fonts/truetype/sazanami/sazanami-mincho.ttf'

   # 以下共通
   blockdiag_antialias = True
   seqdiag_fontpath = blockdiag_fontpath
   seqdiag_antialias = True
   nwdiag_fontpath = blockdiag_fontpath
   nwdiag_antialias = True
   actdiag_fontpath = blockdiag_fontpath
   actdiag_antialias = True

iPhone, iPad アプリ開発勉強会 資料

不定期で木曜日に開催している「iPhone, iPad アプリ開発勉強会」の発表資料です。

iPhone, iPadアプリ開発勉強会#2
メモリ管理など


iPhone, iPadアプリ開発勉強会#3
基本的な型など

Ubuntu 12.04 on beagleboard-xm Rev.C でErlang動いた

Ubuntu 12.04インストール

正月にAndroid動かしてからほったらしになってたbeagleboard-xmですが、ふと思い立ってubuntu入れてみました。
beagleboard-xmへのubuntuのインストールは至って簡単。
ここを参考にさせていただいたらなにもつまづかずにできました。

$ wget http://cdimage.ubuntu.com/releases/12.04/release/ubuntu-12.04-preinstalled-desktop-armhf+omap.img.gz
$ gunzip ubuntu-12.04-preinstalled-desktop-armhf+omap.img.gz 

SDカードを挿入してsyslogでデバイスを確認。sdcでした.
ddコマンドでイメージファイルをSDカードにコピー。

$ sudo dd bs=4M if=ubuntu-12.04-preinstalled-desktop-armhf+omap.img of=/dev/sdc

以上w あとはこのSDカードをbeagleboard-xmに差して起動。初回はシステム設定ですが、起動までに結構時間がかかります。

さすがにunityだと重くてもっさり加減が我慢できなかったので、以前開発マシンで使っていたWindowMakerを入れることにしました。

$ sudo apt-get install wmaker wmaker-data menu

一旦ログアウトして、ログイン時にWindowMakerを選択すればWindowMakerが起動します。
で、上の写真みたいな感じに。
unityではものすごくモッサリしてましたが、WindowMakerに変えたらサクサク動きます。

あと全体的にSDカードの読み書きがボトルネックになっている感は否めません。最初立ち上がりが遅いと思ってましたが、原因はCPUよりSDカードからの読み込みにありそうです。
なのでSDカードはケチらずに速いやつを買うことをお勧めします。

Erlang RB15B02のインストール
このままじゃなんなんで、Erlang入れてみました。Erlangてサーバーのイメージ強いですけど、てか実際その方面での使用がほとんどでしょうけど、実は組み込みに有利な特性ももってるようです。

いわゆるソフトリアルタイム性ですが、Erlangは各プロセスごとにGCを持ってるそうなので、GCが走ったために全体がグッと止まるということがないようです。試してませんがw

あと、そのプロセスごとのGCはプロセスが破棄されるときに、そのプロセスが確保していた領域を開放するそうなので、メモリをたくさん使う処理は、それ用にプロセス作ってそこで処理をして、そのプロセスを破棄すればGCなのに任意のタイミングでのメモリ解放ができてかつ、それが他のプロセスに、ソフトリアルタイムのレベルでは影響しないとかなんとか。

で、入れてみるわけですが、普通に入りました。
aptであったのですが、なんかそれだと面白くないのでソースから入れてみました。
以前落としてたotp_src_R15B02をbeagleboard上にscpして

$ tar xvzf otp_src_R15B02.tar.gz
$ cd otp_src_R15B02/
$ sudo apt-get install libncurses5 libncurses5-dev g++ libssl-dev libcrypto++-dev
$ ./configure --enable-threads --enable-kernel-poll --disable-hipe --without-javac --with-ssl --prefix=/usr/local/erlang/R15B02
$ make
$ sudo make install
$ sudo ln -s /usr/local/erlang/R15B02/bin/* /usr/local/bin/

さすがにコンパイルには時間かかったので、ほっといて寝てましたが、翌朝見たら無事完了してました。
試しに自分が書いたコード落としてみても問題なくコンパイル、動作しました。

あとはこんなの書いてプロセスがたくさん起動してみたりとか
process_test.erl

-module(process_test).

-export([go/1]).

%% 実行開始
go(Count) ->
  %% 引数で渡された数のプロセスを新たに生成する
  Fun = fun(_) -> spawn_link(fun() -> recv() end) end,
  PidList = lists:map(Fun, lists:seq(1, Count)),

  %% 全てのプロセスにメッセージを送信
  send_messages(PidList),
  io:format("message sent to ~p processes.~n", [Count]),

  %% 全てのプロセスからの応答メッセージを受信
  recv_messages(Count),
  io:format("all message returned, ok.~n").

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 基底パターン。全てのプロセスにメッセージ送信完了
send_messages([]) ->
  ok;

%% 再帰しながら各プロセスにメッセージを送信
send_messages([Pid | TailPid]) ->
  Pid ! {hello, self()},
  send_messages(TailPid).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 基底パターン。全てのプロセスから応答メッセージを受信完了
recv_messages(0) ->
  ok;

%% 再帰しながら各プロセスからの応答メッセージを受信
recv_messages(Count) ->
  receive
    {ok, _Pid} -> ok
  end,
  recv_messages(Count - 1). 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 生成されたプロセス側で実行されるメッセージ受信待機関数
recv() ->
  receive
    {hello, From} -> From ! {ok, self()}
  end. 

実行結果葉こんな感じ。

shin@beagle-ubuntu:~/src/process_test$ erl
Erlang R15B02 (erts-5.9.2) [source] [async-threads:0] [kernel-poll:false]

Eshell V5.9.2  (abort with ^G)
1> c(process_test).
{ok,process_test}
2> 
2> timer:tc(process_test, go, [1000]).
message sent to 1000 processes.
all message returned, ok.
{88348,ok}
3> 
3> 
3> timer:tc(process_test, go, [10000]).
message sent to 10000 processes.
all message returned, ok.
{966369,ok}
4> 
4> 
4> timer:tc(process_test, go, [30000]).
message sent to 30000 processes.
all message returned, ok.
{1426422,ok}

時間の単位はマイクロセカンドなんで、1万プロセス立ち上げて全てのプロセスにメッセージ送って返ってくるまで約0.9秒。30000プロセスなら1.4秒。
同じことをMacBookPro With Ubuntu だと

Erlang R15B02 (erts-5.9.2) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false]

Eshell V5.9.2  (abort with ^G)
1> c(process_test).
{ok,process_test}
2>                       
2> timer:tc(process_test, go, [1000]).
message sent to 1000 processes.
all message returned, ok.
{8334,ok}
3> 
3> 
3> timer:tc(process_test, go, [10000]).
message sent to 10000 processes.
all message returned, ok.
{74601,ok}
4> 
4> 
4> timer:tc(process_test, go, [30000]).
message sent to 30000 processes.
all message returned, ok.
{225231,ok}

さすがに差があります。クロック数だけでなくコア数の差も効いているのでしょうか。
それでもあれだけの数のプロセスが比較的短い時間で立ち上がるのが確認できました。

もう眠いので今日はここまで。

メモ: Redisをジョブキューとして使う

Redisについて
Redisはいわゆるオンメモリで動作して永続化もしてくれる高速なキーバリューストアですが、ノティフィケーションのような機能ももってます。
実はジョブキューのようなものは無いかなと最初はRabbitMQを調べていたのですが、そういやRedisにそういう使い方できそうなコマンドがあったような。と思ってみてみたらありました。

コマンド
該当のコマンドはPUBLISHとSUBSCRIBEです。

  1. SUBSCRIBEは現在のコネクションで特定のキーワードの通知が来るのを待機開始するコマンド
  2. PUBLISHは通知を送信するコマンド

です。

具体的には

SUBSCRIBE foo

とするとキーワードfooで通知を待ち受け、

PUBLISH foo hoge

とするとhogeというメッセージとともにSUBSCRIBEしているコネクションにメッセージを送ります。

実際にコマンドラインからやってみましょう。Redisに付属するクライアントredis-cliを使います。srcディレクトリのナカニあります。
Redisはローカルホストの標準ポート(6379)で動作しているものとします。

まずは待ち受け用のクライアントを起動します。

./redis-cli

"foo"というキーワードでSUBSCRIBEコマンドを発行します。

SUBSCRIBE foo

Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "foo"
3) (integer) 1

どうやら待ち受けがはじまりました。

続いて通知送信のためのクライアントを起動します。同じくredis-cli

./redis-cli

PUBLISHコマンドで通知を送信します。

PUBLISH foo hoge

すぐさま最初のSUBSCRIBEしたクライアントで通知を受け取りました。

SUBSCRIBE foo
Reading messages... (press Ctrl-C to quit)
...

1) "message"
2) "foo"
3) "hoge"

どうやらうまくいきました。
それではErlangのRedisクライアントライブラリeredisで試してみます。

eredisでRedisのPub/Subコマンドを試す
さて、eredisを使う場合は普通はeredis:q(Conn, [コマンド | 引数リスト]) などとしますが、待ち受けようにSUBSCRIBEする場合はこれだとエラーが出ます。
ではどうするかというと、eredis_sub_clientというのを使うのですが、この使い方の説明用とでもいうか、eredis_subというものが用意されています。名前からこれが本命かのようですが、あくまでサンプルとしてみた用が良さそうです。が、折角用意してあるので使ってみます。

eredisをmakeした上で、erlコマンドで対話モードを起動します。

erl -pa ebin

起動したらeredis_sub:sub_example() を実行します。

eredis_sub:sub_example().

この中で何をしているかというと、コードはこんな感じになってます。

sub_example() ->
    {ok, Sub} = start_link(),
    Receiver = spawn_link(fun () ->
                                  controlling_process(Sub),
                                  subscribe(Sub, [<<"foo">>]),
                                  receiver(Sub)
                          end),
    {Sub, Receiver}.
  1. 最初にstart_linkでeredis_sub_client:start_link/6を呼んでgen_serverを起動
  2. 続いて別プロセスをspawn
  3. spawnしたプロセス内でcontrolling_process/0を呼んで通知がこのspawnしたプロセスに来るように設定
  4. 続いてsubscrive/2を呼んで"foo"というキーワードの通知を待つ事をredisに知らせる
  5. 最後にreceive/1を呼んで再帰ループでメッセージを待機します。

送信はさっきのredis-cliからやってもいいのですが、折角なのでこっちもeredisから。送信側は従来通りのコマンド発行でOKです。

{ok, C} = eredis:start_link().
eredis:q(C, ["PUBLISH", "foo", "helo"]).

PUBLISHした直後に待ち受けていたノードで

received {message,<<"foo">>,<<"helo">>,<0.33.0>}

と表示されれば成功です。
実際には表示だけしてもしょうがないので、ここで受け取ったメッセージからなんらかの処理をしたりする事になると思います。例えば別にリストを用意しておいて、そこになんらかのフォーマットでジョブを入れてからPUBLISHで通知、事前にSUBSCRIBEしていたプロセスが通知を受け取ると同時にリストからジョブを取り出して処理...とかもできそうです。

あと、当然待ち受け側と送信側が別の言語で動作していてもいいですね。ジョブキューのシステムとしてはRabbitMQが有名ですが、ちょっとしたことなら案外こっちが単純で良かったりするかもしれません。