コミケ告知

サークル活動の詳細は circle タグの記事へ。
2014年10月31日金曜日

C87当選

◎貴サークル「浜風もっこす」は、火曜日 西地区“く”ブロック-23a に配置されました。


 3日目の西という、また若干行きづらい配置ではありますが、今年は最終日が大晦日ではないのが救いですね。
 夏はバックアップ体制に不備がある状態で作業していたのに気付かず見事に吹き飛ばしてしまい、予定していたネットワーク本が出せない悲しい事態になりましたが、既にバックアップ体制は整えました。冬はいつものネットワーク本、艦これ攻略本のツートップをしっかり形に出来るよう、制作を進めていきます。ネットワーク本の既刊も、また少し刷って持っていくつもり。

 続報はまた、内容が固まっていき次第新規に投稿します。よろしくお願いします。
2014年10月30日木曜日

歌舞伎座.tech#5「すごいErlangをゆかいに学ぶ会」に参加してきた

いつのまにかAkkaやらErlangやら、並行処理系のフレームワークを扱っているドワンゴさん所の勉強会。今回はErlangということで、ささっと参加申し込みして楽しみにしていました。

公式:  歌舞伎座.tech#5「すごいErlangをゆかいに学ぶ会」 - connpass

発表枠

(以下の表は、現時点での公式イベントページより引用)
発表者資料
sile@ドワンゴ「ドワンゴでのホットデプロイ事例」

「なぜERLANGにしたのか」(前回資料)
mururu@学生「Elixir 1.0」
shino@Basho「本番環境を止めずに問題を安全に解析する方法」
voluntas@時雨堂「Erlang/OTP + Lua」

Elixirが文法や機能説明である以外は、実戦で使われた事例から一般的に使えそうな話を引っこ抜いて話してくれるような、実用性の非常に高い濃い内容でした。Erlang/OTPという存在自体が、実装は枯れていて、いかにシステムを構築するかを考えればよいフレームワークなので、勉強会も自然とそうなるんでしょうね。


LT枠


(以下の表は、現時点での公式イベントページより引用)
発表者資料
山口能迪@ymotongpoo「『すごいErlangゆかいに学ぼう』でゆかいなところ」
t_egg(Comming Soon)「Euler with Erlang」
KOU_CHANG@ドワンゴErlang Utility Library (GitHub Repository)

LTはゆるい雑談な感じで。(感想とくになし)

懇親会

ピザと飲み物(缶アルコールとソフトドリンク)が配給されました。木曜日だというのに、23時まで酒飲みながらgdgdして、みなさん翌日大丈夫だったんでしょうか?
Elixirの講演をされた方を探していくつか聞いてみようかと思ったけれども、うっかり顔を覚えておくのを忘れたので、そのへんで適当に雑談。何の偶然か同業者の方を発見してしまい、Erlangとはあまり関係ないところで楽しかったです。
Erlangはすぐに「他の人がメンテできねえ」に到着してしまって、小さくて若者・精鋭がそろうところか、好き勝手にやれる研究部門でもないと、なかなか難しいですね。Scalaと違って、見た目がカッコよくて人が釣れる言語ならまだ可能性はあるかもしれないですが…

総括

Erlangを実際に使っている人にとっては、非常に実用性の高いイベントです。
Erlangを触ったことがない人の場合は…どうでしょうね。概要説明などせずに実際の問題に入るので、講演の概要くらいしか頭に残らないのでは。それなら家でスライドナナメ読みしたほうがマシw 細かい特性差を除くと機能はAkkaに近いので、Actor Modelの使いどころについてはあちらで慣れてくる手もありかも。

Erlang関係の勉強会は半年に一回くらいは開催する、というような話が聞こえてきた気がするので、次回以降にも期待しましょう。個人的にはその頃までに、Elixirで何か小物を作れたらいいなーと目論んでおります。


2014年10月13日月曜日

Scalaの実行コンテキストとFuture, blocking

ScalaのFutureというのは、下から(プロセッサに近い方からの)目線でいえば、処理をスレッドプールに丸投げする仕組みです。.NETにも似たような仕組みがありますね。

参考:Scala公式ドキュメント Futureの項目 (en / jp)

Futureの実行環境として、Scalaではscala.concurrent.ExecutionContext.Implicits.global というものがあり、implicitなExecutionContextとして、デフォルトでよさげなものを用意してくれます。このExecutionContextの挙動を確かめるために、ちょっとしたコードを書きました。
基本は、第一引数で指定した数のFutureを生成して走らせるだけです。Future内では、実行タイミングとスレッド番号を表示します。
% scala FutureBehaviorChecker.scala 1
Processors: 8
Thread active: 3
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   27 ->   228] at  10
% scala FutureBehaviorChecker.scala 6
Processors: 8
Thread active: 8
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   28 ->   228] at  10
Finished: 05 [   31 ->   231] at  14
Finished: 02 [   31 ->   231] at  13
Finished: 03 [   31 ->   231] at  16
Finished: 04 [   31 ->   231] at  17
Finished: 01 [   31 ->   231] at  12

ExecutionContext.Implicits.globalの挙動

スレッドプール内のスレッド数は、プロセッサ数と同じだけの上限を持つようです。
% scala FutureBehaviorChecker.scala 10 
Processors: 8
Thread active: 9
Current Thread: 1
Mode: sleep without blocking{}.
Finished: 00 [   33 ->   234] at  10
Finished: 04 [   37 ->   237] at  14
Finished: 03 [   37 ->   237] at  13
Finished: 05 [   37 ->   237] at  15
Finished: 02 [   37 ->   237] at  12
Finished: 01 [   36 ->   236] at  11
Finished: 06 [   37 ->   237] at  16
Finished: 07 [   37 ->   237] at  17
Finished: 08 [  246 ->   446] at  10
Finished: 09 [  246 ->   446] at  14
9個目以降は、全スレッドがブロックしているので詰まってますね。
まあデフォルトなんてこんなものか。と自前のExecutorContext指定の方法を調べかかりましたが、そこに手を出す前にもっと簡単な方法がありました。

blockingの指定

本家のドキュメント内ではさらりと流されていますが、ブロッキングしてしまうような迷惑なFutureに対しては、明示的にブロッキング動作をするものだと指定できるようです。

参考: multithreading - Asynchronous IO in Scala with futures - Stack Overflow

自作のテストコードでは、第二引数に何か与えると、Thread.sleepをblockingで囲んだコードが走ります。
% scala FutureBehaviorChecker.scala 10 1
Processors: 8
Thread active: 12
Current Thread: 1
Mode: sleep with blocking{}.
Finished: 04 [   33 ->   234] at  15
Finished: 06 [   33 ->   234] at  16
Finished: 07 [   34 ->   234] at  17
Finished: 01 [   33 ->   234] at  11
Finished: 09 [   35 ->   235] at  19
Finished: 05 [   33 ->   234] at  14
Finished: 00 [   29 ->   234] at  20
Finished: 08 [   35 ->   235] at  18
Finished: 02 [   33 ->   235] at  12
Finished: 03 [   33 ->   234] at  13

使用するスレッド数が増えてますね。長くなるのでわざわざここには貼りませんが、100個同時に走らせれば100スレッド生成されるようです。スレッドを立てるので使用するリソースは増えるものの、全体がブロックすることはなくなります。
この大量に生成されるスレッドは、Futureごとにスレッドをひとつ立てるのではなく、あくまでもスレッドプールに増えるものです。Future実行に使用したスレッドは一定時間ごとにじわじわとshutdownされていきます。Futureを使った後、定期的にスレッド数をprintしてみると、じわじわと減っていくのがわかります。


まとめ

  • Futureが走るスレッド数は有限
  • ブロックする操作 or 時間がかかる操作なら、とりあえずはblockingをつける
ブロッキング操作するFutureが多い場合は、java.util.concurrent.Executors関連調べて、もっとまじめに実行コンテキストの管理をした方が良いのではないかと思います。ブロックする操作の先にある何か(DBやネットワーク接続等)で扱える並列性よりもたくさん並べても、意味ないので…。
プロトタイプや遊びで組むぶんには、blockingに頼ってしまってもいいかな。
2014年10月11日土曜日

Akkaの挙動確認用の小物を作った

AkkaのActorスケジューリング周りの挙動を確認するための、ちょっとしたものを作りました。

概要

Actorの数、OSスレッドの数、Actor1個あたりに飛ばすメッセージ数を指定して回し、簡単なレポートを出力します。Actorのメッセージハンドリングが、どのスレッドでどんな順番で実行されたのかが表示されます。
適当に時間がかかるように、Actorはメッセージを受け取るごとにフィボナッチ数を求めています。この実験では別にsleepでも良いんですが、後々試したいことがいくつかあることと、OSやVMによるスレッドのスケジューリングに手を出したくないことから、この方法にしました。

Akkaの設定

参考:Configuration — Akka Documentation

スレッド数の設定

スレッド数は固定値を指定するものではなく「factor」「parallelism-min」「parallelism-max」の3項目と、実行環境で認識されたプロセッサー数によって決定します。まず最初に使われるのがfactorで、(プロセッサー数 * factor)を切り上げた値が用いられます。その後、parallelism-minparallelism-maxの指定範囲内にない場合は、指定範囲に収まるように値が補正されます。minよりmaxの方が小さい場合、maxが優先されるようです。

あくまでもfactorで計算された値が基本であるため、max設定値だけ大きくしてもスレッドは増えません
このテストプログラムでは、引数-apf, -apmin, -apmaxによって、この3項目を設定可能です。

スループットの指定

Actorがスレッドを手放すまでに処理するメッセージの数を設定するのが、akkaのthroughputです。パッと見では、用語から挙動を想像するのが難しいような気がします。

AkkaのActorスケジューリングに用いられる単位は、メッセージです。Actorが(receiveで)メッセージを受け取ると、どこかのスレッドに割り当てられ、receiveのブロックから抜けると、Akkaのシステム側に制御を委ねます。以下の例では、Msg1を受信したらdoFoo()を実行して終了、Msg2を受信したらdoBar1()とdoBar2()を実行して終了。
class HogeActor extends Actor {
  override def receive = {
    case Msg1 =>
      doFoo()
    case Msg2 =>
      doBar1()
      doBar2()
  }
}
スレッドを明け渡すまでに、メッセージをいくつ連続で処理するかを示す設定値がthroughputです。メッセージがActorのメールボックスに5個届いていたとして、throughputが5以上あれば、一気に全部処理します。throughputが1であれば、1個処理したところで、Akkaのシステムに一度制御を返します。他にメッセージ処理を待っているActorがいれば、そちらにスレッドを譲ることになります。
スレッド上で走るActorの入れ替えにはコストがかかるので、一気に走り続けた方が性能面では有利です。しかし、あるActorが居座ったままだと、他のActorがいつまで経っても処理を始められないかもしれません。Configuration説明ページのコメントに set to 1 for as fair as possible とあるように、このパラメーターはthroughputとfairnessのトレードオフです。ここまで説明してようやく、パラメーター名の意味がわかります。
throughputパラメーターは、冒頭のテストプログラムでは -at で設定できます。メッセージの数を多めに、スレッドの数をActorの数より少なく設定すると、何がどうなるのか観察できます。

補足

各WorkerActorの始動に1つメッセージを消費しているため、最初の1サイクルはメッセージ1個分ずれます。