Unixドメインソケットを使ったプロセスの同時実行制御(排他制御)について考えてみました。
以下のサイトで紹介されている 抽象名前空間
というものを利用することにしました。
https://siguniang.wordpress.com/2012/04/29/unix-domain-socket-address-types/
ロックファイルを使うと意図せずにロックファイルが残ったときに実行ができなくなる可能性がありますが、 この方法ならプロセスとだけ結びつく(毎回ソケットファイルを削除する必要がない)ためそういった心配がありません。
あと対象のパスの存在や書込権限を考慮しなくてよいのは大きなメリットですね。
以下は排他的に「1秒おきに実行中であることを5回表示してくれる」すてきなプログラムです。
only.pyというすてきな名前で保存します。
import socket
# 先頭をNULLにすると抽象名前空間というものになるらしいです
SOCKET_NAME = '\0test'
def main():
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
# 既にbind中だと例外が発生する
s.bind(SOCKET_NAME)
import time
for i in range(5):
print '実行中だよ(%s)\n' % i
time.sleep(1)
except socket.error:
# 例外が発生したらほかで実行されているということ
print('だめだよ!')
finally:
# とりあえず閉じる
s.close()
if __name__ == '__main__':
main()
※Linuxでしか動作しないようです。
3並列で実行するとこんな感じになります。すごい見づらい
-
$ ./only.py 実行中だよ(0) 実行中だよ(1) 実行中だよ(2) 実行中だよ(3) 実行中だよ(4) $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ!
-
$ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ ./only.py 実行中だよ(0) 実行中だよ(1) 実行中だよ(2) 実行中だよ(3) 実行中だよ(4) $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ!
-
$ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ .only.py だめだよ! $ ./only.py 実行中だよ(0) 実行中だよ(1) 実行中だよ(2) 実行中だよ(3) 実行中だよ(4)
こんな感じになります。(2行で1秒のイメージ)
socketというとacceptとかconnectとか通信することを考えがちですが、こういった使い方もできるんですねー
Gistにアップしました https://gist.github.com/righ/f1800f4d223aed72fb56
デコレータの第1引数でソケット名、第2引数でエラー時の処理を関数で渡します。 (せっかくなのでクラスベースのデコレータで実装してみました)
例えば下記のようにすると上と同じ結果になります(たぶん
import only
def damedayo():
print 'だめだよ!'
@only.only('\0test', damedayo)
def main():
import time
for i in range(5):
print '実行中だよ(%s)\n' % i
time.sleep(1)
if __name__ == '__main__':
main()