JythonでActor modelプログラミング
ScalaのActorライブラリを使えば、Actor modelに基づく簡単に並行処理プログラムを書くことが出来る。ところで、Wikipedia日本語版のアクターモデルの項は英語版の古い版の訳のようだが、ところどころおかしい。
試しに、2つのActorが数字をカウントするプログラムを書いて実行してみた。
$ scalac ActorTest.scala $ scala ActorTest c1: 1 c2: 1 c2: 2 c1: 2 c2: 3 c2: 4 c2: 5 c2: 6 c2: 7 c2: 8 c2: 9 c2: 10 c1: 3 c1: 4 c1: 5 c1: 6 c1: 7 c1: 8 c1: 9 c1: 10
2つのActorの出力が混ざっている。MacBookPro5,5 (Intel Core 2 Duo)で動かしたので、それぞれのActorが各CPUに配置されて実行されている(はずである)。
Akka
普段使っているPythonかJythonでもScalaのActorライブラリを使うように簡単に並行処理プログラムを書きたい。Pythonで並行処理プログラミングをするにはmultiprocessing — Process-based parallelism — Python 3.7.2 documentationがあるが、Jythonは標準では(まだ)このような便利なモジュールは提供されていない。
Web検索をして、Java用のActorライブラリのAkkaを見つけた。最近version 1.0になったらしい。JyhtonはJavaライブラリを使えるので、Akkaも使えるだろうと思って、書いてみた。
$ CLASSPATH=java/lib/akka-modules-1.0/akka-modules-1.0.jar:$CLASSPATH $ jython akka_test.py [main] [INFO] [2011-02-25 21:26:41,161] a.c.Config$: Config [akka.conf] loaded from the application classpath. Starting actor... Starting actor... [main] [INFO] [2011-02-25 21:26:41,454] a.d.LazyExecutorServiceWrapper: Lazily initializing ExecutorService for [main] [INFO] [2011-02-25 21:26:41,458] a.d.LazyExecutorServiceWrapper: Lazily initializing ExecutorService for From client> ar1 org.python.proxies.__main__$MyActor$1@6b6c14c0 0 org.python.proxies.__main__$MyActor$1@6b6c14c0 1 From client> ar2 org.python.proxies.__main__$MyActor$1@6b6c14c0 2 org.python.proxies.__main__$MyActor$1@4c68059 0 org.python.proxies.__main__$MyActor$1@4c68059 1 org.python.proxies.__main__$MyActor$1@4c68059 2 org.python.proxies.__main__$MyActor$1@4c68059 3 org.python.proxies.__main__$MyActor$1@4c68059 4 org.python.proxies.__main__$MyActor$1@4c68059 5 org.python.proxies.__main__$MyActor$1@4c68059 6 org.python.proxies.__main__$MyActor$1@4c68059 7 org.python.proxies.__main__$MyActor$1@4c68059 8 org.python.proxies.__main__$MyActor$1@4c68059 9 org.python.proxies.__main__$MyActor$1@6b6c14c0 3 org.python.proxies.__main__$MyActor$1@6b6c14c0 4 org.python.proxies.__main__$MyActor$1@6b6c14c0 5 org.python.proxies.__main__$MyActor$1@6b6c14c0 6 org.python.proxies.__main__$MyActor$1@6b6c14c0 7 org.python.proxies.__main__$MyActor$1@6b6c14c0 8 org.python.proxies.__main__$MyActor$1@6b6c14c0 9 [main] [INFO] [2011-02-25 21:26:41,476] a.a.Scheduler$: Starting up Scheduler Stopping actor... Stopping actor... [akka:event-driven:dispatcher:7fdcf470-40da-11e0-9983-d49a20f05f9e-1] [WARN] [2011-02-25 21:26:42,485] a.d.ThreadBasedDispatcher: ThreadBasedDispatcher[akka:event-driven:dispatcher:7fdcf470-40da-11e0-9983-d49a20f05f9e] is shut down, ignoring the rest of the messages in the mailbox of []
あれこれとログが出力されていて見にくいが、2つのActorが並列に動いていることが分かる。
AkkaのWebサイトで提供されているドキュメントは不十分だが、ライブラリのakka-modules-1.0/lib_managed/compile/
, akka-modules-1.0/deploy/
, akka-modules-1.0/dist/
にドキュメントがある。JavaかScala向けAPIとして提供されているが、Jythonでも使えることを確認してみた。
Remote Actor
$ jython akka_remote_test.py [main] [INFO] [2011-02-25 21:57:20,618] a.c.Config$: Config [akka.conf] loaded from the application classpath. [main] [INFO] [2011-02-25 21:57:21,536] a.d.LazyExecutorServiceWrapper: Lazily initializing ExecutorService for client> Hello [main] [INFO] [2011-02-25 21:57:21,577] a.a.Scheduler$: Starting up Scheduler
STM(Software Transactional Memory) and Agent
STMは同期かつ協調的に働く。Agentは非同期かつ非協調的に働く。これらの機能はClojureの機能にインスパイアされている。
$ jython akka_stm_test.py 2011/02/25 22:00:16 org.multiverse.api.GlobalStmInstance <clinit> 情報: Initializing GlobalStmInstance using factoryMethod 'org.multiverse.stms.alpha.AlphaStm.createFast'. 2011/02/25 22:00:16 org.multiverse.stms.alpha.AlphaStm <init> 情報: Created a new AlphaStm instance 2011/02/25 22:00:16 org.multiverse.api.GlobalStmInstance <clinit> 情報: Successfully initialized GlobalStmInstance using factoryMethod 'org.multiverse.stms.alpha.AlphaStm.createFast'. [main] [INFO] [2011-02-25 22:00:19,123] a.c.Config$: Config [akka.conf] loaded from the application classpath. STM1> 1 STM1> 2 STM1> 3 STM1> 4 STM1> 5 STM2> 6 STM2> 7 STM2> 8 STM2> 9 STM2> 10 agent> 2 [main] [INFO] [2011-02-25 22:00:19,458] a.d.LazyExecutorServiceWrapper: Lazily initializing ExecutorService for agent send()> 8 agent send(f)> 16 [akka:event-driven:dispatcher:global-3] [INFO] [2011-02-25 22:00:21,488] a.d.LazyExecutorServiceWrapper: Lazily initializing ExecutorService for [akka:event-driven:dispatcher:33f73ac0-40df-11e0-92f8-d49a20f05f9e-4] [INFO] [2011-02-25 22:00:21,505] a.a.Scheduler$: Starting up Scheduler agent sendOff> 32 [akka:event-driven:dispatcher:33f73ac0-40df-11e0-92f8-d49a20f05f9e-4] [WARN] [2011-02-25 22:00:22,509] a.d.ThreadBasedDispatcher: ThreadBasedDispatcher[akka:event-driven:dispatcher:33f73ac0-40df-11e0-92f8-d49a20f05f9e] is shut down, ignoring the rest of the messages in the mailbox of [] agent map> 64 agent foreach> 96
JythonでAkkaが提供する機能をひと通り使うことが出来ることを確認した。これを使ってMapReduceを実装してみたい。