wxPythonでマルチスレッドプログラミング

なんだかんだで,Pythonが好きです.楽です.ちょっとGUIのツールを作る必要にかられたので,wxPythonで作りました.GUIのライブラリに何を使うかいつも迷うんですが,もうC++いじるのつかれた,Javaは死ぬほどいじってるので,offのときくらいPythonを.で,pyQtwxPythonで迷うんですが,よりopenっぽいwxPythonを選択.適当に作って適当に動くところまでは楽ですね.最近Flexをいじくる機会があったのですが,ああいうふうにGUIXML,ロジックはプログラミング言語で,というスタイルもいいですね,というかソッチの方がいいですね.ボタンおくたびに,インスタンスを明示的に生成するのに不毛感を感じるようになってしまった.

さてここまでが前振りで,重い処理を中断するためのインターフェースを備えるためにはマルチスレッド化しないといけません.ここではまります.実は,昔wxWidgetsを使った時もやはりはまったので,そこにwx系のハマリポイントがあるみたい.Qt使えばよかったかなぁ・・・・.


まず最初に,wxWidgetsにあるはずのwxThreadというクラスが,どういうわけかwxPythonにはありません.謎です.これは普通にthreding.Threadを使えということらしい.そこは置いといて,とりえあえずwxWidgetsのThreadのヘルプを見てみると,メインスレッド意外は"secondary threads"と呼ばれて,この中からGUIをいじるときにはwxGuiMutexEnterとwxGuiMutexLeaveを呼べ,と書いてある.

wxPythonのヘルプにもちゃんとこの2つのメソッドは存在する.コメントなしだけどな!

しかし,wxWidgetsのドキュメントには,これはオススメの方法じゃないからPostEvent呼んでくれ,とつづいている.GUI操作に関する命令は全部イベントハンドラの中に入れましょう,という指針だ.これはこれでありだし,一貫しているので変な気はしない.やはり別スレッドでいじるのはちゃんとmutexlockかけていても(ちゃんとインプリされてるのか怪しいという意味で)不安だ.しかし,かといってPostEventってどやって使えと.そもそも,こんな面倒なことしたくない・・・.この辺,どうやるのがベストなんだろうかと思ったが,いかんせんドキュメントがコメントなしという自体なのでググルしかない.ようやく見つけたのが以下の記事.

CallAfterに関数を渡すと,GUIメインスレッドでその関数を実行してくれるよ,という事らしい.すばらしい.これで,直接呼び出していた関数を,単にCallAfterに渡せば良いだけになった.ここにもPostEventとCallAfterの使い方が書いてある.wiki見れ,ということなんだろうか.この界隈は.

メデタシめでたし,ということで,早速実行してみたら見事にGUIが操作を受け付けなくなった! これはヒドイ.ちゃんとスレッド別にしてるし,おかしいなぁと思ってsleep文を入れたら直った.ここからは予想だが,イベントキューがCallAfterでいっぱいになって,通常のGUI操作をさばけなくなったと予想される.ひどいなぁ・・・.本当はもっと別のいい方法があるのかもしれないが,どうせ個人で使うツールなので動いたしこれでいいや.他の方法を知っているご親切な方がいらっしゃいましたら,コメントなどをいただけると幸い.

以下,実際のコード.sleepを抜くと固まる.

        wx.CallAfter(self.parent.AppendResult, f, index, pos, line)
        sleep(0.001)

結論.やっぱりドキュメントの充実してないライブラリは使うべきじゃない.書籍もあるらしいが,こんな日曜プログラミングにしか使わないライブラリにお金かけて分厚い本を読み込むのもなぁ,という気がしてします.pyQtをつかえば,あるいは良かったのかもしれない.なんだかんだ,巡り巡ってやっぱりJavaが一番,という結論になりそう.うーん・・・.