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

普段使っているPythonJythonでも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/にドキュメントがある。JavaScala向け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を実装してみたい。