マルチプロセスで並列化したのは、実はThreadごとにDBとのconnectionを張る方法がわからなかったからだ。単純にThreadの中で最初にmake-connectionしていたら落っこちた1。
そうか、*connection*は別空間にならないのか。
でもどうやれば、いいんだろう。たぶんパッケージもThreadごとになるわけじゃないだろうし。そもそもThreadごとに変数をもてるのか?
Emacsのバッファローカル変数のように。
うーん、*connection*をクロージャー化すれば、いけるような気もするけれど、方向性を誤っているような予感がする。で、結局、そのあたりのあれやこれやが解決しないと、マルチスレッドでの並列化は無理だった。
別にマルチプロセスで問題はないのだけど。
いや問題はあるのか。ループでプロセスを四個ずつ立ち上げるようにしているので、途中で終了することができない。Ctrl-Cで中断するしかなく、なんか、これが気持ち悪い。
ググってもわからず、悩んでいるとき、cl-dbiのソースをのぞいたらまさにそういうコードがあった。別に明確にサポートしているわけではなく、それ関係がエクスポートされているわけでもないのだけど、考え方は了解した。
なるほど、ハッシュテーブルを用意してThread自身をキーにしてconnectionを管理すれば、いいのか。じゃ、こうか。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defvar *connection-pool* (make-hash-table :test 'eq)) | |
(defvar *lock* (make-lock)) | |
(defun conn(&optional(file #P"~/keiba.init")) | |
"カレントのスレッドに紐づいたpostgresへのconnectionを返却する。" | |
(with-lock-held (*lock*) | |
(or (gethash (bt:current-thread) *connection-pool*) | |
(setf (gethash (bt:current-thread) *connection-pool*) | |
(with-open-file (stream file) | |
(apply #'dbi:connect (read stream))))))) |
*connection*を(conn)に変更すれば、OK——そのはず2。