Hatena::ブログ(Diary)

初学者の箸置 このページをアンテナに追加 RSSフィード

2018-07-06

[] 大雨のお陰様で

いろいろシッチャカメッチャカ

2018-07-03

[]Request, replyパターン

途中途中で更新していく。

前回のhello <-> world なパターンは絵にするとこんな感じ。最も単純かつよく使う Request/Reply パターンと呼ぶそうな。

f:id:tkuro:20180703094739j:image

その前に、衝撃を受けたので書いとく

REQタイプ

本の説明はいきなり last-peer とか fair queue とか出てきて混乱したんだけど、実は単純な話で zmq ではソケットタイプによって使用方法にある程度縛りを設けて、通信をパターン化しているらしい。、rfc読んだら一発だった。

https://rfc.zeromq.org/spec:28/REQREP/

ZMQ_REQタイプはlock-step round-robin algorithmでリクエスト送信、そのリプライの受信を行う。クライアント側。単純なモデルで信頼性はそれほど必要としない、という前提。

  • 任意数のREP or ROUTER に接続できる。
  • 一度に1メッセージずつ送信-> 返信するモデル

送信パケット

  • 空フレームがデリミタとして追加される(? まだいまいちイメージできてないがダムフレームで送るのかな)
  • 1つ以上のデータフレームでメッセージが構成される
  • 相手がいないとかで送信できないときは、ブロックするかエラーを返す
  • 送信できなかったメッセージも破棄されない

返信パケット

  • last-peer(つまりREQを送ったやつ)から到着したメッセージのみ受理
    • それ以外のhostからのメッセージはしれっと捨てる

ZMQ_REP はいわゆるfair queue。つまり小さいほうから詰め込んでいく考え方。WFQじゃないのか。

REPタイプ

REQの受け側。リクエスト受信、そのリプライの送信を行う。

  • 任意個のREQ or DEALER ピアに接続できる
  • メッセージをフィルタや改変しない
  • 一度に1メッセージずつ

受信(リクエスト)パケット

  • アドレスエンベロープは0以上のフレームからなりそれぞれが1つの識別子を持つ
  • 空フレームがデリミタ
  • 1つ以上のデータフレームでメッセージが構成される

受信パケット

返信パケット

  • アプリケーションからの呼び出されて指定されるのを待つ
  • アドレスエンベロープやらデリミタが追加される
  • 発信元に送り返される
  • 発信元が死んでいたりしたら、しれっと捨てるか、エラーを返す。

ついでなのでROUTER

REPの非同期版。DEALERクライアントとお話しするサーバのベースになることが多い。

明示的にアドレス使って、複数のピアと通信できる。

  • 任意個のREQ, DEALER, ROUTERと接続できる
  • 接続したピアに対して 1つのダブルキューを管理する

うーむ、ダブルキューてなに?

あー、理解。送信・受信、両方向キューですね。

  • 自発的送信するときも、リクエストもらうときも ダブルキューを確保する。
    • 送信キューは接続がなくても破棄されない
    • 受信キューは接続が切れたら破棄。
  • 一意の "identity" binary string(?)とやらで各ダブルキューを選択
  • Identity metadata property(?)とやらでピアが名乗る(識別される)ことが可能(なんのこっちゃい)
  • 送受信キューサイズは実行時にリミットを与えられる

受信メッセージは

  • fair queueing
  • 到着メッセージは発信元ダブルキューの識別子が入ったフレームが最初に入る

送信メッセージは

  • 送信メッセージの最初のフレームを破棄してこれをダブルキューの識別子とする- 送信キューに空きがあればそこに入れる
  • キューがない、または空きがなければ、しれっと捨てるかエラー(設定による)
  • ブロックしない

さらについでなのでDEALER

2018-07-01

[]ØMQを復習

  • この名前よく聞くがよく理解もしていない
  • ChangeLogを見ると2013年にやっていたらしい。例によって。
  • jupyter notebook でも使われているらしい

というわけでちゃんと理解しなおしてみようといつものごとくsafaribooksを立ち上げて見た。

使う本はこちら

https://www.safaribooksonline.com/library/view/zeromq/9781782161042/

スタート

we are living in a connected world だそうな。low-levelでは面倒だが、high-levelではスピードが得られにくい。ちょうど中間が欲しい。そればzmqなのさ、という話。savior (救世主)

とか書いてある。ケンシロウめ。

メッセージキューの話

FIFO queue のこと。priority queue てなんだっけ。あれか、レジカウンターでは時間かかる人を後回しにしたほうが平均待ち時間がってやつ。

キューは大規模な分散システムを実現するためのキーファクターだって書いてある。さらに非同期通信(AIO)。リアルタイムでは必須。シングルスレッド上に複数のタスクをマップできる。JavaScriptっぽい。

よくある例としてWebappの話が次に続く。多量のアクセスに対して、シングルスレッドでは捌き切れず、マルチスレッドではDDoSされるとスレッド爆発してしまう。メッセージキューによるAIOならば(キューマシンを分ければ)これらの問題とともに対故障性にもすぐれるとか。

んでZeroMQ

このメッセージキューを実現する仕組みZeroMQ.sockets on steroids.

分散/平行アプリケーションのためのメッセージングライブラリ.

  • 単純さ
  • 性能
  • Brokerlessデザイン

中央集権でないらしい。(という事は対故障生の話は嘘なんでは…)

というわけで 僕らの友達  HelloWorld

サーバ側:

zmqでは全てはコンテキストから生成されるので、まずはこれを作ってソケットを生成する。

まずは準備して、

#include <zmq.h>

int main(int arc, char const *argv[])
{
  void* context = zmq_ctx_new();
  void* respond = zmq_socket(context, ZMQ_REP);

ソケットにアドレスをバインドして、

  zmq_bind(respond, "tcp://*:4040");       printf("Starting waiting...\n");

メッセージループに。

    for (;;) {
        wait_for_hello(respond);
        printf("Received: hello\n");
        sleep(1);
        send_world(respond);
        printf("send: world\n");
    }

終わったら(終わらないけど)後始末。

  zmq_close(respond);
  zmq_ctx_destroy(context);

  return 0;
}

んで肝心の受信の方はこんな感じになる(ちゃんと"hello"か確認してないだろう、というツッコミはちと置いておいて)

void wait_for_hello(void* respond)
{
    zmq_msg_t request;

    zmq_msg_init(&request);
    zmq_msg_recv(&request, respond, 0);
    zmq_msg_close(&request);
}

単純にメッセージを作って、ソケットからrecvするだけ。んで終わったらメッセージは捨てる。

んで送信

void send_world(void* respond)
{
    zmq_msg_t reply;

    zmq_msg_init_size(&reply, strlen("world"));
    memcpy(zmq_msg_data(&reply), "world", 5);
    zmq_msg_send(&reply, respond, 0);
    zmq_msg_close(&reply);
}

同じように、基本的にメッセージを作ってソケットに投げつけるイメージ。メンバ変数というかメッセージのバッファを指定してmemcpyすんのがちとめんどいがそれはCだから

基本こんだけ。

https://github.com/tkuro11/zmqtutorial

まとめ

zmqはソケットを直に使うよりは相当に楽に非同期メッセージキューを実現するライブラリで、基本的に高レベルな操作を使ってかけるが、考え方はこれまでのモデルと大差ないので覚えやすい。ソケットの種類がすごいいっぱいあるけど、これはマルチキャストとかの対Nに対応しているから、といったところかなー。まだぼんやりしている。

次回はその機能てんこ盛りなソケットタイプから request reply の仕組みあたりかな。

2017-09-08

Rust入門

同僚の人に「Rustっておもしろい?」と聞かれて気になったので、ここやってみる。

https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/

しかしだ。twitter検索してみたら

2012年02月06日(月)

Rustのclosureって全然closureじゃない気がするんだけど。upvarアクセスそのままでは出来ないようだし。どこがpythonと違うのよ。これは単に僕の理解が足りないだけ?

posted at 18:56:23 削除

2月6日@tkuro11

Rust, 流石に type str=int とかは単に無視かw。Naggingかよ。せめて怒ってよw

posted at 18:04:55 削除

2012年02月01日(水)2 tweetssource

2月1日@tkuro11

Rust, writer_utilとかナニモノ

posted at 16:54:06 削除

2月1日@tkuro11

焼けてきたtkuro11@tkuro11

合成と一致検証の合間にRustコンパイルするなど。

posted at 16:26:48 削除

5年も前にやってたらしく、完全に忘れている自分に旋律戦慄などした。

環境構築

まずはインストール

流行りのshellダイレクトインストール(と僕が勝手に呼んでいる)方法がサポートされているようで精神衛生上よろしいのでこれにする。

 % curl -sSF https://sh.rustup.rs | sh

なんでこれが好きかというとこれって覚えやすいのでどこに行っても使えるから、です。

これで rustc とか cargo(ビルドシステム)がインストールされる。

 % source ~/.cargo/env

するとパスとかの環境変数設定が完了。いや、とかじゃなくて中身見てみると本当にパスの設定しかしていないw

さらにvim用の環境をこさえる。ここを参考にした。

http://qiita.com/hinagishi/items/f43538ce8120e483077e

cargo install --git 'https://github.com/phildawes/racer.git'
cargo install --git https://github.com/rust-lang-nursery/rustfmt

結構時間かかる。racerは補完のため。rustfmtは自動整形のため。

わあ楽チンと思ったのもつかの間。rustfmtの方でみょーなエラーにひっかかる

error[E0554]: #[feature] may not be used on the stable release channel
  --> /home/tkuro/.cargo/git/checkouts/rustfmt-5390e0ead582d971/a1fd68d/src/lib.rs:11:1
   |
11 | #![feature(rustc_private)]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^

よくわかんないけど、nightly buildじゃないとアカンということかな。というわけでrustupでコンパイラを入れ替える。

 % rustup install nightly
 % rustup default nightly

rust version 1.22.0-nightly (368122087 2017-09-06)になった。

あ、よく考えたらnightlyまでいかんでもbetaでいいのか・・・

以下でも行けるみたいだけど overrideって何を上書きするんだろう。あとで調べよう

 % rustup override set nightly

とりあえずこれでコード補完とシンタックスハイライト、自動整形までおk

その他気になるもの

Compiling aho-corasick v0.6.3

なんだろうこれ

コード書く

までもなく cargoで自動生成するとテンプレートが生成される。

 % cargo new --bin hero_world
 % cd hero_world
 % cargo run 
   Compiling hero_world v0.1.0 (file:///home/tkuro/Rust/hero_world)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
     Running `target/debug/hero_world`
Hello, world!
 % cat src/main.rs
fn main() {
    println!("Hello, world!");
}

全然前のこと思い出せないけど、あまりきれいな言語じゃないなー。!は関数じゃなく

マクロなんだそうな。

cargoの作ってくれるテンプレートは プロジェクトルートに src/があってこの中の

main.rsがエントリポイント(おそらくルートのCargo.tomlで変えられるんだろう)。

cargo build とか runとかすると target/debugとかにバイナリが生成される。

生成物でかい

swordfish% ls -l target/debug/hero_world  
-rwxr-xr-x 2 tkuro tkuro 3885344  9月  8 07:45 target/debug/hero_world*

言語にダイブするのは次のエントリで。

まとめ

  • 結構簡単に環境が構築できる
  • rustupのおかげで環境の管理が簡単
  • cargoがモダンな感じに開発をサポートしてくれる。
  • 言語はどうも省略形が多いが、アノテーションとか#で簡単そう

2017-08-12

[haskell] twice twice twice

 > twice twice succ 0
 4
 > twice twice twice succ 0
 16

でビビったり。とかなさけない。

しばらくいじってなかったらだいぶ感覚鈍っていて、というか以前やった時もあんまり理解できていなかったんだなと少し反省を重ねつつも、全く成長しない自分に相変わらずの嫌悪感を持つふりをしながらも、結局は自分に甘いじじい青二才

だなーと思いながら、 twice を重ねた時の挙動をやっとこさ理解できたのでメモ。

定義から

 twice f x = f (f x)

ということはカリーな感じで

 twice  f = \x -> f (f x)

2つならどーだ

        twice twice
        ==> \f -> twice (twice f) 
        ==> \f -> (\x -> (twice f) ((twice f) x))
        ==> \f -> (\x -> (\y -> (f (f y)) ((\y -> (f (f y))) x) ))
        ==> \f -> (\x -> (\y -> (f (f y)) (f (f x))))
        ==> \f -> (\x -> (f (f (f (f x)))) )

あーなるほど。

本番

        twice twice twice
        ==> \f -> (\x -> (f (f (f (f x)))) ) twice 
        ==> \x -> (twice (twice (twice (twice x))))

ぎゃー。しかし twice ( twice x ) が上の通りであることを考えれば

        ==> \x -> \f -> { (f (f (f (f x))))) } が4段分

で結局 16となるわけか。

概念としては

((twice twice) twice) succ)

とゆーのは素直に 「二回(二回を(二回分 ( succ))) する」でよいわけか。

んでとどのつまり 2^2^2と考えればよいわけですね。

じゃあtripleなら

3^3^3になるのかな、と思ったけど7,625,597,484,987だからだめだーと

> triple f x = f ( f( f x))
> triple succ 0
3
> triple triple succ 0
27

3^3で日和ってみた。あと (3^3)^3とか

> triple (triple triple) succ 0
19683

ちょうどひっくり返るのかひっくり返らない。そのまま!いややっぱりひっくり返る!ww(アホか僕) おもしろい。

他人のワーク

先に文献レビューをするのがアカデミックなのでしょうが、ダメ人間なので後から探したりなど。

http://spivey.oriel.ox.ac.uk/corner/Twice_twice_twice

まんまのがあった。しかも処理系にpretty printさせてるのでカッケー

駄菓子菓子、Haskell関数適用は左結合だから

reduce (Ap (Ap Twice f) x) = return (Ap f (Ap f x))

これはおかしいんじゃないだろうか?これだと 後ろのTwiceが先に評価されない?

余談ですが

Tonight, Tonight, Tonight はけっこー好きです。

D

追記:

ややこしいことしてたけど、

 twice f = f.f

とすれば思っきし自明。悩む価値もなかったりなんぞした。

 twice twice f ==> (twice . twice) f ==> twice ( f.f ) = (f.f).(f.f)
 twice twice twice f ==> (twice twice twice) f 
              { ( twice twice f ) = f.f.f.fより }
                                  ==> (twice.twice.twice.twice) f
                                  ==> (twice.twice.twice (f . f))
                                  ==> (twice.twice (f.f) . (f.f))
                                  ==> (twice (f.f).(f.f) . (f.f).(f.f))
                                  ==> ((f.f).(f.f).(f.f).(f.f) . (f.f).(f.f).(f.f).(f.f))