3
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

SmalltalkからLuaをevalする

はじめに

Pharo SmalltalkからTarantool経由でLuaを実行してみようという話です。

Tarantoolをインストール

Tarantoolって何よ? ということですが、DBMSの機能を備えたLuaの実行環境です。ロシア製ということもあって日本ではまだマイナーですが、向こうでは大手のネット企業であるMail.Ru Groupが使ったりもしているようです。

https://tarantool.org/try.html
でいきなりWebブラウザから試せます。

3+4 と打ってenterすると

7 が返ってきますね。

正直ここで試すのは苦痛なのでとっとと本物をインストールします。

macOSであれば

brew install tarantool --HEAD

とします。

その他OS用のインストール方法はこちらです。

Tarantoolの起動

では動かしてみます。

tarantool とターミナルで打ってみるとプロンプトが出てきます。

tarantool> 3 + 4

7が返ってきました。

tarantool-console.png

tutorial()と打つとインタラクティブなチュートリアルが始まったりしますが、今回は割愛します。

DBMS部分を動かしてみましょう。

box.cfg{listen = 3301}

3301ポートで接続を受け付けるようになりました。

tarantool-listen.png

次に外部接続用のユーザを作成します。'taran'というユーザIDで、パスワードは'talk'にします。

box.schema.user.create('taran', {password = 'talk'})

さらに権限も付与します。データの読み取りだけでなく、スキーマやインデックスの作成、evalもできるようにしておきます。

box.schema.user.grant('taran', 'read,write,execute', 'universe')

これでクライアントが接続できる環境が整いました。

Tarantalkを入れる

TarantalkとはPharo版のTarantoolクライアントです。これによりPharo SmalltalkからTarantoolにつないで、Luaのプログラムを実行したり、DBMSの機能を使ったりすることが可能になります。

TarantoolのクライアントはConnectorと呼ばれています。Smalltalk以外にも、JavaやPython、ErlangやC#などいろいろな言語用のConnnectorが提供されています。

TarantalkはPharoのCatalog Browserからインストールできます。"Tools"->"Catalog Browser"で開き、検索窓のところに"taran"と打てば見つかるでしょう。

catalog-browser.png

右クリックで"Install stable version"を選ぶと入ります。

install-stable-version.png

もしくはPlaygroundを開き、以下を"Do it"でも良いです。

Metacello new
    smalltalkhubUser: 'Pharo' project: 'MetaRepoForPharo50';
    configuration: 'Tarantalk';
    version: #stable;
    load.

接続の確認

Tarantoolには認証機能があるので、接続の際には、ホスト、ポート番号の他、ユーザIDとパスワードをURIの形で指定します。

tarantalk := TrTarantalk connect: 'taran:talk@localhost:3301'.

"Print it"してみると接続状態を確認できます。

tarantool-connected.png

接続を切るにはreleaseを送ります。

tarantalk release.

tarantool-released.png

TrTarantalk releaseAllで、複数のクライアントをまとめてreleaseすることもできます。色々試した結果、エラーなどでTarantoolへの接続状態がおかしくなった時に使うと便利です。

Luaプログラムの実行

DBMSとしての利用は次回に回すとして、ここではLuaのプログラムをPharoから実行してみることにします。evalWithReturn:を使います。

tarantalk := TrTarantalk connect: 'taran:talk@localhost:3301'.
(tarantalk evalWithReturn: '3+4') value.

#(7)が返ってきました。evalWithReturn:は必ずArrayの形で戻り値が返ります。これはLuaの関数が多値を返すことができるためです。

return7.png

valueと送っているのは、TarantoolのAPIが非同期になっているからです。valueは非同期APIを同期的に使うための便利メッセージです。これにより値が返るのをブロックして待つようになります。

非同期としてそのまま使うにはコールバックをifDone:ifFailedで指定します。

(tarantalk evalWithReturn: '3+4')
    ifDone: [:ret | ret inspect] ifFailed: [:err | err inspect].

"Do it"するとevalの終了時に別のスレッドでインスペクタが上がります。非同期APIはブロックが最小限になるのでスループットが上がるという利点があります。が、記述が面倒なので以後は主にvalueを使います。

inspect7.png

今度は乱数を得てみましょう。

(tarantalk evalWithReturn: 'math.random()') value.

#(0.698852465637164)と返ってきました。
rand.png

もうちょっとコラボ感を出したいので、Luaからの値をもとに、Smalltalk側で現在の時間を生成してみたいと思います。別にDateAndTime nowで良いのですがあえてやります。

(tarantalk evalWithReturn: 'os.time()') valueThen: [ :val |
    DateAndTime fromUnixTime: val first
].

valueThen:valueのバリエーションで、Luaからの値を加工したい時に使います。os.time()の結果が数値の配列として帰るのでfirstで取り出し、DataAntTime class>>fromUnixTime:に渡しているというわけです。

"Inspect it"すると現在時間となっていることを確認できます。Unix epochからの秒数なので、ナノ秒の部分(nanos)は入っていません。

inspect-lua-dateandtime.png

ちなみにDateAndTime nowだとこうなります。

inspect-st-dateandtime.png

Lua側に値を渡す

今度はSmalltalk側からLuaのプログラムに値を渡してみる例です。
値を渡すためにはevalWithReturn:arguments:を使います。Lua側も(...)で任意の引数を受け取れるように書いておく必要があります。

Smalltalkにも正規表現ライブラリはありますが、あえてLuaの文字列パターンマッチを利用してみます。

(tarantalk evalWithReturn: 'string.match(...)' arguments: {'こんにちはSmalltalkの世界へ'. 'S%w+'}) value

'S'で始まるalphanumericな部分が取り出されます。'Smalltalk'ですね。

requireしてみる

TarantoolはLuaの標準ライブラリ以外にも、便利ライブラリを色々と搭載しているので、requireして使ってみたいと思います。

搭載ライブラリについてはこちらに情報があります。
https://tarantool.org/doc/reference/reference_lua/index.html

digestのmoduleを使い、SHA-512のハッシュ値を求めてみたいと思います。Pharoには標準でSHA-256はあるのですが、SHA-512は入っていないのです。ようやくLuaを使う意味が出てきました。:slight_smile:

(tarantalk evalWithReturn: '(require("digest").sha512_hex(...))' arguments: {'こんにちはSmalltalkの世界へ'}) valueThen: [ :val |
    val first
].

それらしい結果が返ってきます。

sha512.png

速さは?

興味本位で速さを測ってみました。1000回ほど繰り返してみます。

[1000 timesRepeat: [  
(tarantalk evalWithReturn: '(require("digest").sha512_hex(...))' arguments: {'こんにちはSmalltalkの世界へ'}) valueThen: [ :val |
    val first
].
]] timeToRun.

perf.png

2013年のMacBook Air (1.7 GHz Intel Core i7)で0:00:00:00.334となりました。1秒間で3000送信くらいはこなせそうです。FFIには遠く及びませんがお気軽には使えるでしょう。

まとめ

Tarantalkというライブラリを使ってSmalltalkからLuaを実行してみようという話でした。豊富なLuaのエコシステムをPharo Smalltalkから利用できるというメリットがあります。
DBMSとしても面白い特徴がありますので、それは次回以降に紹介します。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?